Response-side HTTP hardening: security headers + safe-by-default CORS (fail-closed)
| Tier | infrastructure |
| Role | unclassified (baselined) |
| Path | crates/infrastructure/hardening |
| Edition | 2021 |
| Targets | infrastructure_hardening |
| Public items | 4 across 1 module |
| Tests | 9 |
What it is for
Response-side HTTP hardening for axum/tower services.
Companion to infrastructure-waf (request-side: signatures, rate-limit, honeypots). This crate owns the response posture — security headers and safe-by-default CORS — with a fail-closed config: a missing or partial config deserializes to a fully hardened posture.
# Ordering (important)
The header layer must be the outermost layer so its headers apply to every response, including short-circuit responses from inner layers such as a WAF 403. With tower::ServiceBuilder the FIRST .layer() is outermost:
use tower::ServiceBuilder;
let svc = ServiceBuilder::new()
.layer(infrastructure_hardening::recommended()) // outermost: headers on ALL responses
// .layer(cors).layer(ceilings).layer(waf) // inner
.service(router);
Note: chained axum::Router::layer() orders in REVERSE of ServiceBuilder (last-added is outermost), so prefer an explicit ServiceBuilder for the security stack to avoid getting the order backwards.
Capabilities
crate root
Response-side HTTP hardening for axum/tower services.
| Item |
|---|
fn recommended() -> SecurityHeadersLayer |
cors (other)
Safe-by-default CORS builders.
| Item |
|---|
fn allowlist(origins : Vec <HeaderValue>) -> CorsLayer |
fn allowlist_with_credentials(origins : Vec <HeaderValue>) -> CorsLayer |
fn dangerously_reflect_any_origin() -> CorsLayer |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
infrastructure_hardening
cors
Public surface
`crate root`
| Item | What it is |
|---|---|
fn recommended() -> SecurityHeadersLayer | Secure-default response-header layer: HSTS, nosniff, X-Frame-Options, Referrer-Policy, and Permissions-Policy |
`cors`
| Item | What it is |
|---|---|
fn allowlist(origins : Vec <HeaderValue>) -> CorsLayer | CORS restricted to an explicit origin allowlist |
fn allowlist_with_credentials(origins : Vec <HeaderValue>) -> CorsLayer | CORS restricted to an explicit origin allowlist, with credentials |
fn dangerously_reflect_any_origin() -> CorsLayer | DANGEROUS: reflects any request Origin |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
{FrameOptions,HardeningConfig} | config::{FrameOptions,HardeningConfig} |
{SecurityHeadersLayer,SecurityHeadersService} | headers::{SecurityHeadersLayer,SecurityHeadersService} |
Boundary
Depends on no other workspace tier.
Shares tier infrastructure with 82 other crates: infrastructure-acquire, infrastructure-adapters-google-calendar, infrastructure-adapters-google-gmail, infrastructure-adapters-google-places, infrastructure-adapters-google-trends, infrastructure-adapters-shodan, infrastructure-adapters-yelp, infrastructure-agent, … (82 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | infrastructure |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/infrastructure/hardening |
| Vocabulary in force (lexicon) | current |
Dependencies
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
http | ^1.1 | — | no | always |
serde | ^1 | derive | no | always |
tower | ^0.5 | util | no | always |
tower-http | ^0.6 | fs, trace, cors, request-id, cors | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
axum | ^0.7 | multipart | no | always |
serde_json | ^1 | — | no | always |
tokio | ^1 | full | no | always |
Build. None.
Depended on by. 2 workspace crates.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_security["application-security"] -->|uses| SELF n_infrastructure_security_scan["infrastructure-security-scan"] -->|uses| SELF SELF["infrastructure-hardening"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| lib | infrastructure_hardening | `src/lib.rs` |
Error model
No public error type was detected: no public item declares a type named *Error, and no public signature returns one.
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | none detected |
| database access | none detected |
| network I/O | yes |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
2 workspace crates depend on this one: application-security, infrastructure-security-scan.
Verification
| Kind | Count |
|---|---|
| Unit tests | 9 |
| Integration tests | 0 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 1 | 0 | 1 |
cors | 3 | 0 | 2 |
What the tests establish, by name:
deny_frame_option_serializes—src/config.rsempty_config_is_fail_closed—src/config.rsheader_map_has_secure_defaults—src/config.rsunknown_field_is_rejected—src/config.rsallowlist_allows_listed_origin_and_blocks_others—src/cors.rscredentialed_allowlist_scopes_credentials_to_listed_origins—src/cors.rsreflect_any_origin_mirrors_but_never_carries_credentials—src/cors.rsheaders_applied_even_to_403_block—src/headers.rsheaders_applied_to_inner_response—src/headers.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 4 | 4 |
Public modules with a //! block | 1 | 1 |
pie showData
title Public items with rustdoc
"Documented" : 4
"No rustdoc detected" : 0
Metrics
| Metric | Value |
|---|---|
| Rust source files | 4 |
| Source lines | 458 |
| Code lines | 331 |
| Public API items | 4 |
| Public modules | 1 |
| Tests | 9 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 4 |
| Workspace reverse dependencies | 2 |
pie showData
title Public API by kind
"function" : 4
pie showData
title Rust source composition
"Code" : 331
"Blank or comment" : 127
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.