feat(mail): add stunnel support for Dovecot and Postfix with configuration and certificate management
This commit is contained in:
@@ -5,6 +5,8 @@ locals {
|
||||
getmail_path = "${local.mail_path}/getmail"
|
||||
postfix_path = "${local.mail_path}/postfix"
|
||||
|
||||
stunnel_tag = "latest"
|
||||
|
||||
getmail_jobs = flatten([
|
||||
for account in var.email_accounts : [
|
||||
for mailbox in account.mailboxes : {
|
||||
@@ -29,8 +31,6 @@ locals {
|
||||
MY_DESTINATION = join(",", [for account in var.email_accounts : account.domain])
|
||||
MY_NETWORKS = "127.0.0.0/8"
|
||||
MAILNAME = "smtp.${var.primary_domain}"
|
||||
DOVECOT_AUTH_ADDRESS = "dovecot-auth.mail.svc.cluster.local"
|
||||
DOVECOT_AUTH_PORT = 31000
|
||||
DOVECOT_LMTP_ADDRESS = "dovecot-lmtp.mail.svc.cluster.local"
|
||||
DOVECOT_LMTP_PORT = 31024
|
||||
LOG_TO_STDOUT = 0
|
||||
@@ -82,6 +82,12 @@ locals {
|
||||
dovecot_config_checksum = sha256(local.dovecot_config)
|
||||
dovecot_users_checksum = sha256(local.dovecot_users)
|
||||
dovecot_sieve_checksum = sha256(local.dovecot_sieve)
|
||||
|
||||
dovecot_stunnel_config = file("${path.module}/resources/dovecot/stunnel.conf")
|
||||
dovecot_stunnel_config_checksum = sha256(local.dovecot_stunnel_config)
|
||||
|
||||
postfix_stunnel_config = file("${path.module}/resources/postfix/stunnel.conf")
|
||||
postfix_stunnel_config_checksum = sha256(local.postfix_stunnel_config)
|
||||
}
|
||||
|
||||
data "external" "password_hasher" {
|
||||
|
||||
@@ -42,6 +42,7 @@ resource "kubernetes_config_map" "dovecot_sieve" {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
resource "kubernetes_deployment" "dovecot" {
|
||||
metadata {
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
@@ -68,6 +69,7 @@ resource "kubernetes_deployment" "dovecot" {
|
||||
annotations = {
|
||||
"checksum/dovecot" = local.dovecot_config_checksum
|
||||
"checksum/sieve" = local.dovecot_sieve_checksum
|
||||
"checksum/stunnel" = local.dovecot_stunnel_config_checksum
|
||||
# Commented out to avoid unnecessary restarts
|
||||
# "checksum/users" = local.dovecot_users_checksum
|
||||
}
|
||||
@@ -82,11 +84,9 @@ resource "kubernetes_deployment" "dovecot" {
|
||||
host_port = 993
|
||||
}
|
||||
port {
|
||||
name = "lmtp"
|
||||
container_port = 31024
|
||||
}
|
||||
port {
|
||||
container_port = 31000
|
||||
}
|
||||
volume_mount {
|
||||
name = "email-storage"
|
||||
mount_path = "/var/mail"
|
||||
@@ -120,6 +120,25 @@ resource "kubernetes_deployment" "dovecot" {
|
||||
read_only = true
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "stunnel"
|
||||
image = "chainguard/stunnel:${local.stunnel_tag}"
|
||||
args = ["/etc/conf/stunnel.conf"]
|
||||
volume_mount {
|
||||
name = "stunnel-config"
|
||||
mount_path = "/etc/conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "stunnel-certs"
|
||||
mount_path = "/etc/ssl/certs/private"
|
||||
read_only = true
|
||||
}
|
||||
port {
|
||||
name = "auth"
|
||||
container_port = 31000
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "email-storage"
|
||||
host_path {
|
||||
@@ -156,6 +175,26 @@ resource "kubernetes_deployment" "dovecot" {
|
||||
secret_name = kubernetes_secret.mail_crypt_certs.metadata[0].name
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "stunnel-config"
|
||||
config_map {
|
||||
name = kubernetes_config_map.stunnel_dovecot.metadata[0].name
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "stunnel-certs"
|
||||
secret {
|
||||
secret_name = kubernetes_manifest.stunnel_cert.manifest["metadata"]["name"]
|
||||
items {
|
||||
key = "tls.crt"
|
||||
path = "tls.crt"
|
||||
}
|
||||
items {
|
||||
key = "tls.key"
|
||||
path = "tls.key"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,9 +242,11 @@ resource "kubernetes_service" "dovecot_lmtp" {
|
||||
app = "dovecot"
|
||||
}
|
||||
port {
|
||||
port = 31024
|
||||
name = "lmtp"
|
||||
port = 31024
|
||||
target_port = 31024
|
||||
}
|
||||
cluster_ip = "None"
|
||||
type = "ClusterIP"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,8 +261,10 @@ resource "kubernetes_service" "dovecot_auth" {
|
||||
app = "dovecot"
|
||||
}
|
||||
port {
|
||||
port = 31000
|
||||
name = "auth"
|
||||
port = 31000
|
||||
target_port = 31000
|
||||
}
|
||||
cluster_ip = "None"
|
||||
type = "ClusterIP"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ resource "kubernetes_deployment" "postfix" {
|
||||
annotations = {
|
||||
"checksum/runconfig" = local.postfix_run_config_checksum
|
||||
"checksum/bccmap" = local.postfix_bcc_map_checksum
|
||||
"checksum/stunnel" = local.postfix_stunnel_config_checksum
|
||||
}
|
||||
}
|
||||
spec {
|
||||
@@ -105,6 +106,23 @@ resource "kubernetes_deployment" "postfix" {
|
||||
read_only = false
|
||||
}
|
||||
}
|
||||
container {
|
||||
name = "stunnel"
|
||||
image = "chainguard/stunnel:${local.stunnel_tag}"
|
||||
args = ["/etc/conf/stunnel.conf"]
|
||||
volume_mount {
|
||||
name = "stunnel-config"
|
||||
mount_path = "/etc/conf/stunnel.conf"
|
||||
sub_path = "stunnel.conf"
|
||||
read_only = true
|
||||
}
|
||||
volume_mount {
|
||||
name = "stunnel-ca"
|
||||
mount_path = "/etc/ssl/certs/ca.pem"
|
||||
sub_path = "ca.pem"
|
||||
read_only = true
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "email-storage"
|
||||
host_path {
|
||||
@@ -135,6 +153,18 @@ resource "kubernetes_deployment" "postfix" {
|
||||
path = "/var/log/postfix"
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "stunnel-config"
|
||||
config_map {
|
||||
name = kubernetes_config_map.stunnel_postfix.metadata[0].name
|
||||
}
|
||||
}
|
||||
volume {
|
||||
name = "stunnel-ca"
|
||||
config_map {
|
||||
name = kubernetes_config_map.ca_pem.metadata[0].name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,13 +140,13 @@ auth_mechanisms = plain login
|
||||
|
||||
service auth {
|
||||
inet_listener auth {
|
||||
port = 31000
|
||||
port = 33100
|
||||
}
|
||||
}
|
||||
|
||||
# LMTP service to store sent emails
|
||||
service lmtp {
|
||||
inet_listener auth {
|
||||
inet_listener lmtp {
|
||||
port = 31024
|
||||
}
|
||||
mail_plugins {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
foreground = yes
|
||||
|
||||
[dovecot-auth]
|
||||
accept = 0.0.0.0:31000
|
||||
connect = 127.0.0.1:33100
|
||||
cert = /etc/ssl/certs/private/tls.crt
|
||||
key = /etc/ssl/certs/private/tls.key
|
||||
@@ -15,14 +15,6 @@ if [ -z "$SMTP_PASSWORD" ]; then
|
||||
echo "SMTP_PASSWORD is required"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$DOVECOT_AUTH_ADDRESS" ]; then
|
||||
echo "DOVECOT_AUTH_ADDRESS is required"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z "$DOVECOT_AUTH_PORT" ]; then
|
||||
echo "DOVECOT_AUTH_PORT is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
postconf -e "myhostname=$MAILNAME"
|
||||
postconf -e "mydomain=$MY_PRIMARY_DOMAIN"
|
||||
@@ -41,7 +33,7 @@ postconf -e "smtp_tls_CAfile=/etc/ssl/certs/ca-certificates.crt"
|
||||
|
||||
# SASL configuration
|
||||
postconf -e "smtpd_sasl_type=dovecot"
|
||||
postconf -e "smtpd_sasl_path=inet:$DOVECOT_AUTH_ADDRESS:$DOVECOT_AUTH_PORT"
|
||||
postconf -e "smtpd_sasl_path=inet:localhost:31000"
|
||||
postconf -e "smtpd_sasl_auth_enable=yes"
|
||||
postconf -e "smtpd_sasl_security_options=noanonymous"
|
||||
postconf -e "smtpd_recipient_restrictions=permit_sasl_authenticated, reject"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
foreground = yes
|
||||
|
||||
[dovecot-auth]
|
||||
client = yes
|
||||
accept = 127.0.0.1:31000
|
||||
connect = dovecot-auth.mail.svc.cluster.local:31000
|
||||
CAfile = /etc/ssl/certs/ca.pem
|
||||
@@ -0,0 +1,49 @@
|
||||
resource "kubernetes_config_map" "stunnel_dovecot" {
|
||||
metadata {
|
||||
name = "stunnel-dovecot"
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
"stunnel.conf" = local.dovecot_stunnel_config
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "stunnel_postfix" {
|
||||
metadata {
|
||||
name = "stunnel-postfix"
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
"stunnel.conf" = local.postfix_stunnel_config
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_manifest" "stunnel_cert" {
|
||||
manifest = {
|
||||
apiVersion = "cert-manager.io/v1"
|
||||
kind = "Certificate"
|
||||
metadata = {
|
||||
name = "stunnel-cert"
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
spec = {
|
||||
secretName = "stunnel-cert"
|
||||
issuerRef = {
|
||||
name = var.issuer
|
||||
kind = "ClusterIssuer"
|
||||
}
|
||||
commonName = "${kubernetes_service.dovecot_auth.metadata[0].name}.${kubernetes_namespace.mail.metadata[0].name}.svc.cluster.local"
|
||||
dnsNames = ["${kubernetes_service.dovecot_auth.metadata[0].name}.${kubernetes_namespace.mail.metadata[0].name}.svc.cluster.local"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "kubernetes_config_map" "ca_pem" {
|
||||
metadata {
|
||||
name = "ca-pem"
|
||||
namespace = kubernetes_namespace.mail.metadata[0].name
|
||||
}
|
||||
data = {
|
||||
"ca.pem" = var.ca_pem
|
||||
}
|
||||
}
|
||||
@@ -80,3 +80,15 @@ variable "mail_crypt_public_key" {
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "issuer" {
|
||||
description = "The issuer for the internal certificate"
|
||||
type = string
|
||||
default = "internal-ca"
|
||||
}
|
||||
|
||||
variable "ca_pem" {
|
||||
description = "The CA PEM certificate"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user