218 lines
7.6 KiB
Bash
Executable File
218 lines
7.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# awsses.sh - Konfiguriert Amazon SES mit SNS->SQS Fanout Architektur & Outbound Tracking
|
|
#
|
|
# Ablauf:
|
|
# 1. SES Domain Identity erstellen/verifizieren
|
|
# 2. Domain mit Configuration Set verknüpfen (für Outbound Tracking)
|
|
# 3. SNS Topic erstellen
|
|
# 4. SNS Topic Policy setzen (damit SES hineinschreiben darf)
|
|
# 5. SQS Queue verbinden (Subscription)
|
|
# 6. SQS Queue Policy setzen (damit SNS hineinschreiben darf)
|
|
# 7. SES Receipt Rule erstellen (S3 Action + SNS Action)
|
|
|
|
set -e
|
|
|
|
# Überprüfen, ob jq installiert ist
|
|
if ! command -v jq &> /dev/null; then
|
|
echo "Fehler: 'jq' ist nicht installiert. Bitte installieren (sudo apt-get install jq)."
|
|
exit 1
|
|
fi
|
|
|
|
# Überprüfen, ob die Domain-Variable gesetzt ist
|
|
if [ -z "$DOMAIN_NAME" ]; then
|
|
echo "Fehler: DOMAIN_NAME ist nicht gesetzt."
|
|
echo "Bitte setzen Sie die Variable mit: export DOMAIN_NAME='IhreDomain.de'"
|
|
exit 1
|
|
fi
|
|
|
|
# Überprüfen, ob S3_BUCKET_NAME gesetzt ist
|
|
if [ -z "$S3_BUCKET_NAME" ]; then
|
|
echo "Warnung: S3_BUCKET_NAME ist nicht gesetzt."
|
|
S3_BUCKET_NAME=$(echo "$DOMAIN_NAME" | tr '.' '-' | awk '{print $0 "-emails"}')
|
|
echo "Generierter Bucket-Name: $S3_BUCKET_NAME"
|
|
fi
|
|
|
|
# Konfiguration
|
|
AWS_REGION=${AWS_REGION:-"us-east-2"}
|
|
EMAIL_PREFIX=${EMAIL_PREFIX:-""}
|
|
CONFIGURATION_SET_NAME="relay-outbound" # Name deines globalen Config Sets
|
|
|
|
# Naming Conventions
|
|
RULE_SET_NAME="bizmatch-ruleset"
|
|
RULE_NAME="store-${DOMAIN_NAME//./-}-to-s3"
|
|
TOPIC_NAME="${DOMAIN_NAME//./-}-topic"
|
|
QUEUE_NAME="${DOMAIN_NAME//./-}-queue"
|
|
|
|
echo "========================================================"
|
|
echo " SES Setup (Full Architecture) für $DOMAIN_NAME"
|
|
echo "========================================================"
|
|
echo "Region: $AWS_REGION"
|
|
echo "S3 Bucket: $S3_BUCKET_NAME"
|
|
echo "Config Set: $CONFIGURATION_SET_NAME"
|
|
echo "--------------------------------------------------------"
|
|
|
|
# ------------------------
|
|
# 1. SES Domain Identität
|
|
# ------------------------
|
|
echo "[1/7] Prüfe SES Domain Identität..."
|
|
|
|
if ! aws sesv2 get-email-identity --email-identity ${DOMAIN_NAME} --region ${AWS_REGION} >/dev/null 2>&1; then
|
|
echo "-> Erstelle Identity..."
|
|
aws sesv2 create-email-identity --email-identity ${DOMAIN_NAME} --region ${AWS_REGION} >/dev/null
|
|
else
|
|
echo "-> Identity existiert bereits."
|
|
fi
|
|
|
|
# Config Updates (Idempotent)
|
|
echo "-> Konfiguriere DKIM & Mail-From..."
|
|
aws sesv2 put-email-identity-dkim-attributes --email-identity ${DOMAIN_NAME} --signing-enabled --region ${AWS_REGION}
|
|
aws sesv2 put-email-identity-mail-from-attributes --email-identity ${DOMAIN_NAME} --mail-from-domain "mail.${DOMAIN_NAME}" --behavior-on-mx-failure USE_DEFAULT_VALUE --region ${AWS_REGION}
|
|
|
|
# ------------------------
|
|
# 2. Configuration Set Verknüpfung (NEU!)
|
|
# ------------------------
|
|
echo "[2/7] Verknüpfe Domain mit Outbound Configuration Set..."
|
|
# Dies sorgt dafür, dass ausgehende Mails getrackt werden (für OOO/Bounces)
|
|
aws sesv2 put-email-identity-configuration-set-attributes \
|
|
--email-identity ${DOMAIN_NAME} \
|
|
--configuration-set-name "$CONFIGURATION_SET_NAME" \
|
|
--region ${AWS_REGION}
|
|
|
|
# ------------------------
|
|
# 3. SNS Topic erstellen
|
|
# ------------------------
|
|
echo "[3/7] Erstelle/Prüfe SNS Topic..."
|
|
TOPIC_ARN=$(aws sns create-topic --name "$TOPIC_NAME" --region "$AWS_REGION" --output text --query 'TopicArn')
|
|
echo "-> Topic ARN: $TOPIC_ARN"
|
|
|
|
# ------------------------
|
|
# 4. SNS Policy (SES -> SNS)
|
|
# ------------------------
|
|
echo "[4/7] Setze SNS Policy (SES darf publishen)..."
|
|
ACCOUNT_ID=$(echo "$TOPIC_ARN" | cut -d: -f5)
|
|
|
|
SNS_POLICY=$(jq -n \
|
|
--arg topic_arn "$TOPIC_ARN" \
|
|
--arg account_id "$ACCOUNT_ID" \
|
|
'{
|
|
Version: "2008-10-17",
|
|
Id: "__default_policy_ID",
|
|
Statement: [
|
|
{
|
|
Sid: "Allow-SES-Publish",
|
|
Effect: "Allow",
|
|
Principal: { Service: "ses.amazonaws.com" },
|
|
Action: "sns:Publish",
|
|
Resource: $topic_arn,
|
|
Condition: {
|
|
StringEquals: { "AWS:SourceAccount": $account_id }
|
|
}
|
|
}
|
|
]
|
|
}' | jq -c .)
|
|
|
|
aws sns set-topic-attributes --topic-arn "$TOPIC_ARN" --attribute-name Policy --attribute-value "$SNS_POLICY" --region "$AWS_REGION"
|
|
|
|
# ------------------------
|
|
# 5. SQS Queue Verbindung
|
|
# ------------------------
|
|
echo "[5/7] Verbinde SQS Queue..."
|
|
|
|
# Queue URL & ARN holen (Queue muss existieren -> create-queue.sh vorher ausführen!)
|
|
QUEUE_URL=$(aws sqs get-queue-url --queue-name "$QUEUE_NAME" --region "$AWS_REGION" --output text --query 'QueueUrl' 2>/dev/null)
|
|
|
|
if [ -z "$QUEUE_URL" ]; then
|
|
echo "FEHLER: Queue $QUEUE_NAME nicht gefunden!"
|
|
echo "Bitte führen Sie erst ./create-queue.sh aus."
|
|
exit 1
|
|
fi
|
|
|
|
QUEUE_ARN=$(aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names QueueArn --region "$AWS_REGION" --output text --query 'Attributes.QueueArn')
|
|
|
|
# Subscription erstellen (Idempotent)
|
|
aws sns subscribe --topic-arn "$TOPIC_ARN" --protocol sqs --notification-endpoint "$QUEUE_ARN" --region "$AWS_REGION" > /dev/null
|
|
|
|
# ------------------------
|
|
# 6. SQS Policy (SNS -> SQS)
|
|
# ------------------------
|
|
echo "[6/7] Setze SQS Policy (SNS darf schreiben)..."
|
|
|
|
SQS_POLICY=$(jq -n \
|
|
--arg queue_arn "$QUEUE_ARN" \
|
|
--arg topic_arn "$TOPIC_ARN" \
|
|
'{
|
|
Version: "2012-10-17",
|
|
Id: "SNS-to-SQS",
|
|
Statement: [
|
|
{
|
|
Sid: "Allow-SNS-SendMessage",
|
|
Effect: "Allow",
|
|
Principal: { Service: "sns.amazonaws.com" },
|
|
Action: "sqs:SendMessage",
|
|
Resource: $queue_arn,
|
|
Condition: {
|
|
ArnEquals: { "aws:SourceArn": $topic_arn }
|
|
}
|
|
}
|
|
]
|
|
}' | jq -c .)
|
|
|
|
# Policy setzen (mit Single-Quote Schutz für AWS CLI)
|
|
aws sqs set-queue-attributes --queue-url "$QUEUE_URL" --attributes Policy="'$SQS_POLICY'" --region "$AWS_REGION"
|
|
|
|
# ------------------------
|
|
# 7. SES Rule Set & Rule
|
|
# ------------------------
|
|
echo "[7/7] Konfiguriere SES Receipt Rule..."
|
|
|
|
# Rule Set prüfen
|
|
RULESET_EXISTS=$(aws ses list-receipt-rule-sets --region ${AWS_REGION} | jq -r '.RuleSets[] | select(.Name == "bizmatch-ruleset") | .Name')
|
|
if [ "$RULESET_EXISTS" != "bizmatch-ruleset" ]; then
|
|
echo "-> Erstelle Rule Set 'bizmatch-ruleset'..."
|
|
aws ses create-receipt-rule-set --rule-set-name "bizmatch-ruleset" --region ${AWS_REGION}
|
|
fi
|
|
|
|
# Rule prüfen/erstellen
|
|
if ! aws ses describe-receipt-rule --rule-set-name "$RULE_SET_NAME" --rule-name "${RULE_NAME}" --region ${AWS_REGION} >/dev/null 2>&1; then
|
|
|
|
echo "-> Erstelle Receipt Rule '${RULE_NAME}'..."
|
|
|
|
# Rule mit S3 Action UND SNS Action
|
|
# HINWEIS: Hier fügen wir initial die Hauptdomain als Recipient hinzu.
|
|
# Denke daran, später ./manage_mail_user.sh sync ... auszuführen!
|
|
aws ses create-receipt-rule --rule-set-name "$RULE_SET_NAME" --rule '{
|
|
"Name": "'"${RULE_NAME}"'",
|
|
"Enabled": true,
|
|
"ScanEnabled": true,
|
|
"Actions": [
|
|
{
|
|
"S3Action": {
|
|
"BucketName": "'"${S3_BUCKET_NAME}"'",
|
|
"ObjectKeyPrefix": "'"${EMAIL_PREFIX}"'"
|
|
}
|
|
},
|
|
{
|
|
"SNSAction": {
|
|
"TopicArn": "'"${TOPIC_ARN}"'",
|
|
"Encoding": "UTF-8"
|
|
}
|
|
}
|
|
],
|
|
"TlsPolicy": "Require",
|
|
"Recipients": ["'"${DOMAIN_NAME}"'"]
|
|
}' --region ${AWS_REGION}
|
|
|
|
else
|
|
echo "-> Receipt Rule '${RULE_NAME}' existiert bereits (Überspringe Erstellung)."
|
|
fi
|
|
|
|
# Rule Set aktivieren
|
|
ACTIVE_RULESET=$(aws ses describe-active-receipt-rule-set --region ${AWS_REGION} | jq -r '.Metadata.Name')
|
|
if [ "$ACTIVE_RULESET" != "bizmatch-ruleset" ]; then
|
|
echo "-> Aktiviere Rule Set..."
|
|
aws ses set-active-receipt-rule-set --rule-set-name "bizmatch-ruleset" --region ${AWS_REGION}
|
|
fi
|
|
|
|
echo "========================================================"
|
|
echo "✅ Setup erfolgreich abgeschlossen für $DOMAIN_NAME"
|
|
echo "========================================================" |