# Security Considerations for Macro Inc.: Defense-in-Depth in Rust Microservices

> Macro Inc. secures Rust microservices with defense-in-depth. Learn about compile-time secret validation, JWT middleware, API keys, and logging on AWS.

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: security
- Published: 2026-08-20

---

**Macro Inc. implements defense-in-depth security through compile-time secret validation, JWT middleware, internal API key authentication, and strict logging discipline across its Rust microservices running on AWS.**

Macro Inc. is a collection of Rust microservices deployed on AWS that treats security as a foundational architectural layer rather than an afterthought. Understanding the **security considerations for Macro Inc.** reveals a defense-in-depth strategy spanning secret management, compile-time validation, and zero-trust networking. The codebase achieves this through a unified `macro_env_var` crate and strict middleware-based authentication patterns.

## Centralized Secret Management with the macro_env_var Crate

All configuration values—including API keys, database URLs, and JWT signing secrets—flow through the **`macro_env_var`** crate. This centralized approach ensures that secrets never appear as plain literals in the source code and are loaded in a single, audited location.

In [`crates/macro_env_var/src/lib.rs`](https://github.com/macro-inc/macro/blob/main/crates/macro_env_var/src/lib.rs) (lines 1‑80, 85‑120), the crate provides the `env_var!` macro and functions `read_env` and `maybe_read_env`. These utilities first check for a JSON blob in the `APP_SECRETS_JSON` environment variable (populated by Doppler) and fall back to the standard process environment. This dual-source pattern guarantees that production secrets remain decoupled from the repository while allowing local development to use standard environment variables.

### Compile-Time Validation of Configuration

The `env_var!` macro generates types that distinguish between **`Runtime`** and **`Comptime`** loading. When a developer invokes `new_comptime()` on a generated type, the compiler validates the secret's presence at build time. If a required secret is missing, the build fails immediately, preventing accidental deployment without necessary credentials.

This compile-time guarantee is implemented in [`crates/macro_env_var/src/lib.rs`](https://github.com/macro-inc/macro/blob/main/crates/macro_env_var/src/lib.rs) (lines 85‑130). The discriminator forces developers to handle configuration errors during the CI/CD pipeline rather than at runtime in production.

## JWT Authentication for External Requests

Incoming HTTP requests are protected by the **`macro_auth`** middleware, which validates JSON Web Tokens before any business logic executes. The `decode_jwt` function in [`crates/macro_auth/src/middleware/decode_jwt.rs`](https://github.com/macro-inc/macro/blob/main/crates/macro_auth/src/middleware/decode_jwt.rs) (lines 1‑80) verifies that tokens are signed with the secret loaded via `macro_env_var`. Invalid tokens are rejected at the edge, ensuring that unauthenticated requests never reach internal handlers.

```rust
use macro_env_var::env_vars;

env_vars! {
    pub struct JwtSigningKey;
}

// Load the key at runtime with fallback to APP_SECRETS_JSON
let jwt_key = JwtSigningKey::new()?;

// Apply the middleware to protect routes
async fn auth_layer<B>(req: axum::http::Request<B>, next: axum::handler::Next<B>) -> impl IntoResponse {
    macro_auth::middleware::decode_jwt(req, next, &jwt_key).await
}

```

## Service-to-Service Authorization via Internal API Keys

For internal communication, services exchange signed **internal API keys** that are also loaded through `macro_env_var`. The `validate_internal_key` function in [`crates/macro_auth/src/internal_api_key.rs`](https://github.com/macro-inc/macro/blob/main/crates/macro_auth/src/internal_api_key.rs) (lines 1‑50) checks these keys and injects a trusted `UserId` into the request context.

This mechanism allows services to authenticate each other without exposing user-level credentials or relying on network perimeter security alone. Each microservice treats internal requests with the same skepticism as external ones, enforcing a zero-trust model inside the cluster.

## Database Access Control and SQL Injection Prevention

Database credentials are retrieved through `macro_env_var` in each service's configuration. For example, [`services/document_storage_service/src/config.rs`](https://github.com/macro-inc/macro/blob/main/services/document_storage_service/src/config.rs) uses the `env_vars!` macro to load connection strings securely.

The codebase never concatenates raw strings into SQL queries. Instead, it uses **SQLx** with compile-time checked macros like `query!` and `query_as!`. This practice ensures that queries match the current database schema and eliminates SQL injection vectors by treating all parameters as bound values rather than interpolated strings.

## AWS Credential Hygiene and CI/CD Security

Static AWS credentials are confined exclusively to CI pipelines. In [`tooling/xtask/crates/xtask_workflows/src/workflows/deploy_all_services.rs`](https://github.com/macro-inc/macro/blob/main/tooling/xtask/crates/xtask_workflows/src/workflows/deploy_all_services.rs) (line 319), deploy scripts use explicit static keys only within controlled CI environments. These keys are injected via `macro_env_var` and never committed to the repository.

Runtime services obtain temporary credentials from the AWS instance metadata service. This distinction limits the blast radius of any potential credential leak, as static keys cannot be extracted from running production containers.

## Logging Discipline to Prevent Secret Leakage

The codebase enforces strict patterns to prevent accidental secret exposure in logs. All error logging uses **`tracing::error!(error = ?e, ...)`**, ensuring that error objects are never interpolated into log strings. When `macro_env_var` encounters a missing variable, it returns a `VarNameErr` that discards the raw value when formatted for logging (lines 176‑184 in [`crates/macro_env_var/src/lib.rs`](https://github.com/macro-inc/macro/blob/main/crates/macro_env_var/src/lib.rs)).

This approach guarantees that even if a secret is malformed or missing, its value never appears in log aggregation systems.

## Zero-Trust Networking Architecture

Each microservice operates within a private VPC and exposes only the necessary HTTP endpoints. Internal adapters—such as those found in connection gateway services—use `macro_env_var` to retrieve AWS credentials without exposing them to the network. Access to internal APIs requires valid internal API keys, ensuring that services trust each other based on cryptographic identity rather than network location.

## Summary

The **security considerations for Macro Inc.** demonstrate a comprehensive defense-in-depth strategy:

- **Secrets are never hard-coded**, flowing exclusively through the audited `macro_env_var` crate
- **Compile-time validation** catches missing configuration during builds, not deployments
- **JWT and internal API keys** provide strong authentication for external users and internal services
- **SQLx compile-time query checks** prevent injection attacks and schema mismatches
- **Logging discipline** ensures sensitive values never appear in error traces
- **Static AWS keys are confined to CI**, while production uses short-lived IAM credentials

## Frequently Asked Questions

### How does Macro Inc. prevent secrets from being hard-coded in the source code?

All secrets are loaded through the `macro_env_var` crate, which reads from the `APP_SECRETS_JSON` environment variable (managed by Doppler) or the process environment. The `env_var!` macro generates types that enforce loading at runtime or compile-time validation, ensuring that plaintext secrets never appear in source files or version control.

### What mechanism ensures that required secrets are present before deployment?

The `new_comptime()` constructor on environment variable types forces a compile-time check. If a required secret is not present in the build environment, the Rust compiler fails immediately. This prevents the deployment of services with missing database credentials, JWT keys, or API tokens.

### How do internal services authenticate with each other without exposing user credentials?

Internal services use signed internal API keys validated by the `validate_internal_key` function in `macro_auth::internal_api_key`. These keys are exchanged via HTTP headers and verified using secrets loaded through `macro_env_var`. Upon validation, the middleware injects a trusted `UserId` into the request context, allowing services to authorize actions without handling raw user passwords or session tokens.

### What prevents SQL injection attacks in the Macro Inc. codebase?

The codebase exclusively uses SQLx macros like `query!` and `query_as!`, which validate SQL syntax and parameter types against the database schema at compile time. This approach eliminates string concatenation in queries and ensures that all user input is treated as bound parameters, effectively mitigating SQL injection risks.