From a3fecd2a89f831184356de1cb10f6e5e14348476 Mon Sep 17 00:00:00 2001 From: Erik Stambaugh Date: Wed, 24 Jan 2024 19:30:24 -0800 Subject: [PATCH] SES credentials work now!!! Wow that was a pain in the butt!! --- Makefile | 2 +- ansible/Makefile | 2 +- ansible/inventory.tmpl.yaml | 3 +- ansible/roles/mastodon/tasks/main.yaml | 4 +- ansible/ses_credentials.py | 68 ++++++++++++++++++++++++++ config.mk.in | 3 ++ terraform/ses.tf | 20 +++++--- 7 files changed, 91 insertions(+), 11 deletions(-) create mode 100755 ansible/ses_credentials.py diff --git a/Makefile b/Makefile index 6ed77ed..b40249d 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ endef default: terraform ansible -ansible: config.mk .s3_iam_credentials +ansible: config.mk .s3_iam_credentials .ses_iam_credentials @$(MAKE) -C $@ terraform: config.mk diff --git a/ansible/Makefile b/ansible/Makefile index cd804c9..c29e682 100644 --- a/ansible/Makefile +++ b/ansible/Makefile @@ -41,7 +41,7 @@ secret_sedline: $(eval SEDLINE := $$(SEDLINE) -e 's/{{S3_IAM_ID}}/$(shell head -1 ../.s3_iam_credentials)/') $(eval SEDLINE := $$(SEDLINE) -e 's/{{S3_IAM_SECRET}}/$(shell tail -1 ../.s3_iam_credentials)/') $(eval SEDLINE := $$(SEDLINE) -e 's/{{SES_IAM_ID}}/$(shell head -1 ../.ses_iam_credentials)/') - $(eval SEDLINE := $$(SEDLINE) -e 's/{{SES_IAM_SECRET}}/$(shell tail -1 ../.ses_iam_credentials)/') + $(eval SEDLINE := $$(SEDLINE) -e 's/{{SES_IAM_SECRET}}/$(shell ./ses_credentials.py `tail -1 ../.ses_iam_credentials` $(AWS_REGION) | sed -e "s/\//\\\\\//g")/') # FIXME: DRY this target diff --git a/ansible/inventory.tmpl.yaml b/ansible/inventory.tmpl.yaml index 7551675..4a8f4e3 100644 --- a/ansible/inventory.tmpl.yaml +++ b/ansible/inventory.tmpl.yaml @@ -21,7 +21,7 @@ social: s3_iam_id: {{S3_IAM_ID}} s3_iam_secret: {{S3_IAM_SECRET}} ses_iam_id: {{SES_IAM_ID}} - ses_iam_secret: {{SES_IAM_SECRET}} + ses_iam_secret: "{{SES_IAM_SECRET}}" #smtp_server: otp_secret: @@ -30,5 +30,6 @@ social: #vapid_private_key: #vapid_public_key: + admin_name: {{ADMIN_NAME}} admin_email: {{ADMIN_EMAIL}} diff --git a/ansible/roles/mastodon/tasks/main.yaml b/ansible/roles/mastodon/tasks/main.yaml index d7bbb72..2fdd249 100644 --- a/ansible/roles/mastodon/tasks/main.yaml +++ b/ansible/roles/mastodon/tasks/main.yaml @@ -150,7 +150,7 @@ register: accountcount - name: create admin account - command: "docker compose exec -it mastodon_web bash -c 'RAILS_ENV=production tootctl accounts create meat --email {{ admin_email }} --confirmed --role Owner'" + command: "docker compose exec -it mastodon_web bash -c 'RAILS_ENV=production tootctl accounts create {{ admin_name }} --email {{ admin_email }} --confirmed --role Owner'" args: chdir: /srv/mastodon when: accountcount.stdout == "1" @@ -173,7 +173,7 @@ - name: reload nginx command: docker exec -t nginx nginx -s reload - when: nginxconf.changed + #when: nginxconf.changed ## --- diff --git a/ansible/ses_credentials.py b/ansible/ses_credentials.py new file mode 100755 index 0000000..a0404dc --- /dev/null +++ b/ansible/ses_credentials.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +import hmac +import hashlib +import base64 +import argparse + +SMTP_REGIONS = [ + "us-east-2", # US East (Ohio) + "us-east-1", # US East (N. Virginia) + "us-west-2", # US West (Oregon) + "ap-south-1", # Asia Pacific (Mumbai) + "ap-northeast-2", # Asia Pacific (Seoul) + "ap-southeast-1", # Asia Pacific (Singapore) + "ap-southeast-2", # Asia Pacific (Sydney) + "ap-northeast-1", # Asia Pacific (Tokyo) + "ca-central-1", # Canada (Central) + "eu-central-1", # Europe (Frankfurt) + "eu-west-1", # Europe (Ireland) + "eu-west-2", # Europe (London) + "eu-south-1", # Europe (Milan) + "eu-north-1", # Europe (Stockholm) + "sa-east-1", # South America (Sao Paulo) + "us-gov-west-1", # AWS GovCloud (US) +] + +# These values are required to calculate the signature. Do not change them. +DATE = "11111111" +SERVICE = "ses" +MESSAGE = "SendRawEmail" +TERMINAL = "aws4_request" +VERSION = 0x04 + + +def sign(key, msg): + return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() + + +def calculate_key(secret_access_key, region): + if region not in SMTP_REGIONS: + raise ValueError(f"The {region} Region doesn't have an SMTP endpoint.") + + signature = sign(("AWS4" + secret_access_key).encode("utf-8"), DATE) + signature = sign(signature, region) + signature = sign(signature, SERVICE) + signature = sign(signature, TERMINAL) + signature = sign(signature, MESSAGE) + signature_and_version = bytes([VERSION]) + signature + smtp_password = base64.b64encode(signature_and_version) + return smtp_password.decode("utf-8") + + +def main(): + parser = argparse.ArgumentParser( + description="Convert a Secret Access Key to an SMTP password." + ) + parser.add_argument("secret", help="The Secret Access Key to convert.") + parser.add_argument( + "region", + help="The AWS Region where the SMTP password will be used.", + choices=SMTP_REGIONS, + ) + args = parser.parse_args() + print(calculate_key(args.secret, args.region)) + + +if __name__ == "__main__": + main() diff --git a/config.mk.in b/config.mk.in index 7e47415..7e6c2c3 100644 --- a/config.mk.in +++ b/config.mk.in @@ -4,6 +4,9 @@ ## Template for configuration. ## The comment preceding any variable is printed as its prompt. +# What is the site admin's mastodon account called? +ADMIN_NAME = + # What is the site admin's email address? ADMIN_EMAIL = diff --git a/terraform/ses.tf b/terraform/ses.tf index fc420d5..50a36f7 100644 --- a/terraform/ses.tf +++ b/terraform/ses.tf @@ -14,13 +14,19 @@ module "ses_zone_records" { records = [ { - name = "_amazonses.${aws_ses_domain_identity.social.id}" + name = "_amazonses" type = "TXT" ttl = "600" records = [ aws_ses_domain_identity.social.verification_token ] }, { - name = local.domain_name + name = "" + type = "MX" + ttl = "600" + records = ["10 feedback-smtp.${local.aws_region}.amazonses.com"] + }, + { + name = "bounce" type = "MX" ttl = "600" records = ["10 feedback-smtp.${local.aws_region}.amazonses.com"] @@ -28,13 +34,13 @@ module "ses_zone_records" { # SPF { - name = aws_ses_domain_mail_from.social.mail_from_domain + name = "bounce" type = "TXT" ttl = "600" - records = [ "v=spf1 include:amazonses.com -all" ] + records = [ "v=spf1 include:amazonses.com ~all" ] }, { - name = local.domain_name + name = "" type = "TXT" ttl = "600" records = [ "v=spf1 include:amazonses.com -all" ] @@ -115,7 +121,8 @@ resource "aws_iam_policy" "send_mail" { data "aws_iam_policy_document" "send_mail" { statement { actions = ["ses:SendRawEmail"] - resources = ["*"] + resources = [ "*" ] + #resources = [ aws_ses_domain_identity.social.arn ] } } @@ -130,6 +137,7 @@ resource "local_file" "ses_secret" { resource "local_file" "ses_id" { filename = ".ses_id" content = "${aws_iam_access_key.ses.id}\n" + #content = "${aws_iam_user.ses.name}\n" }