Support for TLS encryption
This commit is contained in:
42
Cargo.lock
generated
42
Cargo.lock
generated
@@ -240,6 +240,28 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-server"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "495c05f60d6df0093e8fb6e74aa5846a0ad06abaf96d76166283720bf740f8ab"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"bytes",
|
||||
"fs-err",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.75"
|
||||
@@ -815,6 +837,16 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs-err"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d7be93788013f265201256d58f04936a8079ad5dc898743aa20525f503b683"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.31"
|
||||
@@ -2240,6 +2272,15 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.12.0"
|
||||
@@ -3802,6 +3843,7 @@ dependencies = [
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"axum-messages",
|
||||
"axum-server",
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"claims",
|
||||
|
||||
@@ -17,6 +17,7 @@ argon2 = { version = "0.5.3", features = ["std"] }
|
||||
axum = { version = "0.8.4", features = ["macros"] }
|
||||
axum-extra = { version = "0.10.1", features = ["query", "cookie"] }
|
||||
axum-messages = "0.8.0"
|
||||
axum-server = { version = "0.7.2", features = ["tls-rustls-no-provider"] }
|
||||
base64 = "0.22.1"
|
||||
chrono = { version = "0.4.41", default-features = false, features = ["clock"] }
|
||||
config = "0.15.14"
|
||||
|
||||
10
Dockerfile
10
Dockerfile
@@ -7,6 +7,8 @@ RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM chef AS builder
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
RUN apt update -y \
|
||||
&& apt install -y --no-install-recommends clang mold
|
||||
RUN cargo chef cook --release --recipe-path recipe.json
|
||||
COPY . .
|
||||
ENV SQLX_OFFLINE=true
|
||||
@@ -15,10 +17,10 @@ RUN cargo build --release --bin zero2prod
|
||||
FROM debian:bookworm-slim AS runtime
|
||||
WORKDIR /app
|
||||
RUN apt update -y \
|
||||
&& apt install -y --no-install-recommends openssl ca-certificates \
|
||||
&& apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& apt install -y --no-install-recommends openssl ca-certificates \
|
||||
&& apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=builder /app/target/release/zero2prod zero2prod
|
||||
COPY configuration configuration
|
||||
ENV APP_ENVIRONMENT=production
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
application:
|
||||
port: 8000
|
||||
database:
|
||||
database_name: "newsletter"
|
||||
email_client:
|
||||
timeout_milliseconds: 10000
|
||||
base_url: "https://api.mailersend.com"
|
||||
sender_email: "MS_PTrumQ@test-r6ke4n1mmzvgon12.mlsender.net"
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
application:
|
||||
port: 8000
|
||||
host: "127.0.0.1"
|
||||
base_url: "http://127.0.0.1:8000"
|
||||
require_tls: false
|
||||
database:
|
||||
host: "127.0.0.1"
|
||||
port: 5432
|
||||
database_name: "newsletter"
|
||||
username: "postgres"
|
||||
password: "password"
|
||||
require_ssl: false
|
||||
email_client:
|
||||
base_url: "https://api.mailersend.com"
|
||||
sender_email: "MS_PTrumQ@test-r6ke4n1mmzvgon12.mlsender.net"
|
||||
authorization_token: "secret-token"
|
||||
redis_uri: "redis://127.0.0.1:6379"
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
application:
|
||||
host: "0.0.0.0"
|
||||
database:
|
||||
require_ssl: true
|
||||
email_client:
|
||||
base_url: "https://api.mailersend.com"
|
||||
sender_email: "MS_PTrumQ@test-r6ke4n1mmzvgon12.mlsender.net"
|
||||
|
||||
@@ -69,6 +69,7 @@ pub struct ApplicationSettings {
|
||||
pub port: u16,
|
||||
pub host: String,
|
||||
pub base_url: String,
|
||||
pub require_tls: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
|
||||
@@ -4,7 +4,7 @@ use zero2prod::{
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), std::io::Error> {
|
||||
async fn main() -> Result<(), anyhow::Error> {
|
||||
init_subscriber(std::io::stdout);
|
||||
|
||||
let configuration = get_configuration().expect("Failed to read configuration");
|
||||
|
||||
@@ -79,7 +79,7 @@ impl IntoResponse for SubscribeError {
|
||||
|
||||
#[tracing::instrument(
|
||||
name = "Adding a new subscriber",
|
||||
skip(connection_pool, email_client, base_url, form),
|
||||
skip(messages, connection_pool, email_client, base_url, form),
|
||||
fields(
|
||||
subscriber_email = %form.email,
|
||||
subscriber_name = %form.name
|
||||
|
||||
@@ -9,10 +9,10 @@ use axum::{
|
||||
routing::{get, post},
|
||||
};
|
||||
use axum_messages::MessagesManagerLayer;
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use secrecy::ExposeSecret;
|
||||
use sqlx::{PgPool, postgres::PgPoolOptions};
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use std::{net::TcpListener, sync::Arc};
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tower_sessions::SessionManagerLayer;
|
||||
use tower_sessions_redis_store::{
|
||||
@@ -21,11 +21,6 @@ use tower_sessions_redis_store::{
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct Application {
|
||||
listener: TcpListener,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub connection_pool: PgPool,
|
||||
@@ -33,13 +28,19 @@ pub struct AppState {
|
||||
pub base_url: String,
|
||||
}
|
||||
|
||||
pub struct Application {
|
||||
listener: TcpListener,
|
||||
router: Router,
|
||||
tls_config: Option<RustlsConfig>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
pub async fn build(configuration: Settings) -> Result<Self, std::io::Error> {
|
||||
pub async fn build(configuration: Settings) -> Result<Self, anyhow::Error> {
|
||||
let address = format!(
|
||||
"{}:{}",
|
||||
configuration.application.host, configuration.application.port
|
||||
);
|
||||
let listener = TcpListener::bind(address).await?;
|
||||
// let listener = TcpListener::bind(address).await?;
|
||||
let connection_pool =
|
||||
PgPoolOptions::new().connect_lazy_with(configuration.database.with_db());
|
||||
let email_client = EmailClient::build(configuration.email_client).unwrap();
|
||||
@@ -61,17 +62,46 @@ impl Application {
|
||||
configuration.application.base_url,
|
||||
redis_store,
|
||||
);
|
||||
Ok(Self { listener, router })
|
||||
let tls_config = if configuration.application.require_tls {
|
||||
Some(
|
||||
RustlsConfig::from_pem_file(
|
||||
"/home/alphonse/.certs/fullchain.pem",
|
||||
"/home/alphonse/.certs/privkey.pem",
|
||||
)
|
||||
.await
|
||||
.unwrap(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let listener = TcpListener::bind(address).unwrap();
|
||||
Ok(Self {
|
||||
listener,
|
||||
router,
|
||||
tls_config,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn run_until_stopped(self) -> Result<(), std::io::Error> {
|
||||
tracing::debug!("listening on {}", self.listener.local_addr().unwrap());
|
||||
axum::serve(self.listener, self.router).await
|
||||
tracing::debug!("listening on {}", self.local_addr());
|
||||
if let Some(tls_config) = self.tls_config {
|
||||
axum_server::from_tcp_rustls(self.listener, tls_config)
|
||||
.serve(self.router.into_make_service())
|
||||
.await
|
||||
} else {
|
||||
axum_server::from_tcp(self.listener)
|
||||
.serve(self.router.into_make_service())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_addr(&self) -> String {
|
||||
self.listener.local_addr().unwrap().to_string()
|
||||
}
|
||||
|
||||
pub fn port(&self) -> u16 {
|
||||
self.listener.local_addr().unwrap().port()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn app(
|
||||
|
||||
@@ -87,19 +87,14 @@ impl TestApp {
|
||||
c.email_client.base_url = email_server.uri();
|
||||
c
|
||||
};
|
||||
let local_addr = configuration.application.host.clone();
|
||||
let connection_pool = configure_database(&configuration.database).await;
|
||||
let email_client = EmailClient::build(configuration.email_client.clone()).unwrap();
|
||||
let application = Application::build(configuration)
|
||||
.await
|
||||
.expect("Failed to build application");
|
||||
let local_addr = application.local_addr();
|
||||
let port = local_addr
|
||||
.split(":")
|
||||
.last()
|
||||
.unwrap()
|
||||
.parse::<u16>()
|
||||
.unwrap();
|
||||
let address = format!("http://{}", application.local_addr());
|
||||
let port = application.port();
|
||||
let address = format!("http://{}:{}", local_addr, port);
|
||||
let test_user = TestUser::generate();
|
||||
test_user.store(&connection_pool).await;
|
||||
let api_client = reqwest::Client::builder()
|
||||
|
||||
Reference in New Issue
Block a user