DNS-01 ์ฑŒ๋ฆฐ์ง€ ๋ฐ AWS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Let's Encrypt SSL ์ธ์ฆ์„œ ๊ด€๋ฆฌ ์ž๋™ํ™”

๊ฒŒ์‹œ๋ฌผ์—์„œ๋Š” SSL ์ธ์ฆ์„œ ๊ด€๋ฆฌ๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๋‹จ๊ณ„๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. CA๋ฅผ ์•”ํ˜ธํ™”ํ•˜์ž ์‚ฌ์šฉ DNS-01 ์ฑŒ๋ฆฐ์ง€ ะธ AWS.

acme-dns-route53 ์ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. Let's Encrypt์˜ SSL ์ธ์ฆ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Amazon Certificate Manager์— ์ €์žฅํ•˜๊ณ , Route53 API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ DNS-01 ์ฑŒ๋ฆฐ์ง€๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ , ๋งˆ์ง€๋ง‰์œผ๋กœ SNS์— ์•Œ๋ฆผ์„ ํ‘ธ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ˆ์— acme-dns-route53 AWS Lambda ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๋„ ๋‚ด์žฅ๋˜์–ด ์žˆ์œผ๋ฉฐ ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๊ธ€์€ 4๊ฐœ์˜ ์„น์…˜์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • zip ํŒŒ์ผ ์ƒ์„ฑ;
  • IAM ์—ญํ•  ์ƒ์„ฑ
  • ์‹คํ–‰๋˜๋Š” ๋žŒ๋‹ค ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ acme-dns-route53;
  • ํ•˜๋ฃจ์— 2๋ฒˆ ํ•จ์ˆ˜๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” CloudWatch ํƒ€์ด๋จธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ  : ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ณ ๋žญ 1.9+ ะธ AWS CLI

zip ํŒŒ์ผ ๋งŒ๋“ค๊ธฐ

acme-dns-route53์€ GoLang์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ 1.9 ์ด์ƒ์˜ ๋ฒ„์ „์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํฌํ•จ๋œ zip ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. acme-dns-route53 ๋‚ด๋ถ€์—. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์„ค์น˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. acme-dns-route53 ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ GitHub ์ €์žฅ์†Œ์—์„œ go install:

$ env GOOS=linux GOARCH=amd64 go install github.com/begmaroman/acme-dns-route53

๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” ๋‹ค์Œ ์œ„์น˜์— ์„ค์น˜๋ฉ๋‹ˆ๋‹ค. $GOPATH/bin ์˜ˆ๋ฐฐ ๊ทœ์น™์„œ. ์„ค์น˜ ์ค‘์— ๋‘ ๊ฐ€์ง€ ๋ณ€๊ฒฝ๋œ ํ™˜๊ฒฝ์„ ์ง€์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. GOOS=linux ะธ GOARCH=amd64. ๊ทธ๋“ค์€ Linux OS ๋ฐ amd64 ์•„ํ‚คํ…์ฒ˜์— ์ ํ•ฉํ•œ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ Go ์ปดํŒŒ์ผ๋Ÿฌ์— ๋ถ„๋ช…ํžˆ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด AWS์—์„œ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
AWS์—์„œ๋Š” ์šฐ๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์ด zip ํŒŒ์ผ๋กœ ๋ฐฐํฌ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๋ฏ€๋กœ ๋‹ค์Œ์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. acme-dns-route53.zip ์ƒˆ๋กœ ์„ค์น˜๋œ ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ํฌํ•จ๋  ์•„์นด์ด๋ธŒ:

$ zip -j ~/acme-dns-route53.zip $GOPATH/bin/acme-dns-route53

์ฐธ๊ณ  : ๋ฐ”์ด๋„ˆ๋ฆฌ๋Š” zip ์•„์นด์ด๋ธŒ์˜ ๋ฃจํŠธ์— ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์šฐ๋ฆฌ๋Š” -j ๊นƒ๋ฐœ.

์ด์ œ zip ๋‹‰๋„ค์ž„์„ ๋ฐฐํฌํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚จ์€ ๊ฒƒ์€ ํ•„์š”ํ•œ ๊ถŒํ•œ์ด ์žˆ๋Š” ์—ญํ• ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค.

IAM ์—ญํ•  ์ƒ์„ฑ

์‹คํ–‰ ์ค‘์— ๋žŒ๋‹ค์—์„œ ์š”๊ตฌํ•˜๋Š” ๊ถŒํ•œ์ด ์žˆ๋Š” IAM ์—ญํ• ์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ด ์ •์ฑ…์„ ํ˜ธ์ถœํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. lambda-acme-dns-route53-executor ์ฆ‰์‹œ ๊ทธ๋…€์—๊ฒŒ ๊ธฐ๋ณธ ์—ญํ• ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค. AWSLambdaBasicExecutionRole. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋žŒ๋‹ค๊ฐ€ AWS CloudWatch ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋กœ๊ทธ๋ฅผ ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋จผ์ €, ๋‹น์‚ฌ์˜ ๊ถŒ๋ฆฌ๋ฅผ ์„ค๋ช…ํ•˜๋Š” JSON ํŒŒ์ผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋žŒ๋‹ค ์„œ๋น„์Šค๊ฐ€ ์—ญํ• ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. lambda-acme-dns-route53-executor:

$ touch ~/lambda-acme-dns-route53-executor-policy.json

์šฐ๋ฆฌ ํŒŒ์ผ์˜ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup"
            ],
            "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:<AWS_REGION>:<AWS_ACCOUNT_ID>:log-group:/aws/lambda/acme-dns-route53:*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "route53:ListHostedZones",
                "cloudwatch:PutMetricData",
                "acm:ImportCertificate",
                "acm:ListCertificates"
            ],
            "Resource": "*"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "sns:Publish",
                "route53:GetChange",
                "route53:ChangeResourceRecordSets",
                "acm:ImportCertificate",
                "acm:DescribeCertificate"
            ],
            "Resource": [
                "arn:aws:sns:${var.region}:<AWS_ACCOUNT_ID>:<TOPIC_NAME>",
                "arn:aws:route53:::hostedzone/*",
                "arn:aws:route53:::change/*",
                "arn:aws:acm:<AWS_REGION>:<AWS_ACCOUNT_ID>:certificate/*"
            ]
        }
    ]
}

์ด์ œ ๋ช…๋ น์„ ์‹คํ–‰ํ•ด๋ณด์ž aws iam create-role ์—ญํ• ์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด:

$ aws iam create-role --role-name lambda-acme-dns-route53-executor 
 --assume-role-policy-document ~/lambda-acme-dns-route53-executor-policy.json

์ฐธ๊ณ  : ์ •์ฑ… ARN(Amazon ๋ฆฌ์†Œ์Šค ์ด๋ฆ„)์„ ๊ธฐ์–ตํ•˜์„ธ์š”. ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์—ญํ•  lambda-acme-dns-route53-executor ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฏ€๋กœ ์ด์ œ ์ด์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. aws iam attach-role-policy, ์ •์ฑ… ARN ์ „๋‹ฌ AWSLambdaBasicExecutionRole ๋‹ค์Œ๊ณผ ๊ฐ™์ด

$ aws iam attach-role-policy --role-name lambda-acme-dns-route53-executor 
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

์ฐธ๊ณ  : ๋‹ค๋ฅธ ์ •์ฑ…์ด ํฌํ•จ๋œ ๋ชฉ๋ก์„ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—.

์‹คํ–‰๋˜๋Š” ๋žŒ๋‹ค ํ•จ์ˆ˜ ๋งŒ๋“ค๊ธฐ acme-dns-route53

๋งŒ์„ธ! ์ด์ œ ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ AWS์— ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. aws lambda create-function. ๋žŒ๋‹ค๋Š” ๋‹ค์Œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • AWS_LAMBDA - ๋ถ„๋ช…ํžˆ ํ•ด์ค€๋‹ค acme-dns-route53 ํ•ด๋‹น ์‹คํ–‰์€ AWS Lambda ๋‚ด์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • DOMAINS โ€” ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋„๋ฉ”์ธ ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค.
  • LETSENCRYPT_EMAIL - ํฌํ•จ ์ด๋ฉ”์ผ์„ ์•”ํ˜ธํ™”ํ•˜์ž.
  • NOTIFICATION_TOPIC โ€” SNS ์•Œ๋ฆผ ์ฃผ์ œ ์ด๋ฆ„(์„ ํƒ ์‚ฌํ•ญ).
  • STAGING - ๊ฐ€์น˜์— 1 ์Šคํ…Œ์ด์ง• ํ™˜๊ฒฝ์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • 1024 MB - ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์ด๋ฉฐ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • 900 ์ดˆ(15๋ถ„) - ์‹œ๊ฐ„ ์ดˆ๊ณผ.
  • acme-dns-route53 โ€” ์•„์นด์ด๋ธŒ์— ์žˆ๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
  • fileb://~/acme-dns-route53.zip โ€” ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์•„์นด์ด๋ธŒ์˜ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.

์ด์ œ ๋ฐฐํฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

$ aws lambda create-function 
 --function-name acme-dns-route53 
 --runtime go1.x 
 --role arn:aws:iam::<AWS_ACCOUNT_ID>:role/lambda-acme-dns-route53-executor 
 --environment Variables="{AWS_LAMBDA=1,DOMAINS="example1.com,example2.com",[email protected],STAGING=0,NOTIFICATION_TOPIC=acme-dns-route53-obtained}" 
 --memory-size 1024 
 --timeout 900 
 --handler acme-dns-route53 
 --zip-file fileb://~/acme-dns-route53.zip

 {
     "FunctionName": "acme-dns-route53", 
     "LastModified": "2019-05-03T19:07:09.325+0000", 
     "RevisionId": "e3fadec9-2180-4bff-bb9a-999b1b71a558", 
     "MemorySize": 1024, 
     "Environment": {
         "Variables": {
            "DOMAINS": "example1.com,example2.com", 
            "STAGING": "1", 
            "LETSENCRYPT_EMAIL": "[email protected]", 
            "NOTIFICATION_TOPIC": "acme-dns-route53-obtained", 
            "AWS_LAMBDA": "1"
         }
     }, 
     "Version": "$LATEST", 
     "Role": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/lambda-acme-dns-route53-executor", 
     "Timeout": 900, 
     "Runtime": "go1.x", 
     "TracingConfig": {
         "Mode": "PassThrough"
     }, 
     "CodeSha256": "+2KgE5mh5LGaOsni36pdmPP9O35wgZ6TbddspyaIXXw=", 
     "Description": "", 
     "CodeSize": 8456317,
"FunctionArn": "arn:aws:lambda:us-east-1:<AWS_ACCOUNT_ID>:function:acme-dns-route53", 
     "Handler": "acme-dns-route53"
 }

ํ•˜๋ฃจ์— 2๋ฒˆ ํ•จ์ˆ˜๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” CloudWatch ํƒ€์ด๋จธ ์ƒ์„ฑ

๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋Š” ํ•˜๋ฃจ์— ๋‘ ๋ฒˆ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” cron์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ CloudWatch ๊ทœ์น™์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. schedule_expression.
  • ๋žŒ๋‹ค ํ•จ์ˆ˜์˜ ARN์„ ์ง€์ •ํ•˜์—ฌ ๊ทœ์น™ ๋Œ€์ƒ(์‹คํ–‰ํ•ด์•ผ ํ•˜๋Š” ํ•ญ๋ชฉ)์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ๋žŒ๋‹ค ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๊ทœ์น™์— ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์—๋Š” Terraform ๊ตฌ์„ฑ์„ ์—ฐ๊ฒฐํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” AWS ์ฝ˜์†”์ด๋‚˜ AWS CLI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

# Cloudwatch event rule that runs acme-dns-route53 lambda every 12 hours
resource "aws_cloudwatch_event_rule" "acme_dns_route53_sheduler" {
  name                = "acme-dns-route53-issuer-scheduler"
  schedule_expression = "cron(0 */12 * * ? *)"
}

# Specify the lambda function to run
resource "aws_cloudwatch_event_target" "acme_dns_route53_sheduler_target" {
  rule = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.name}"
  arn  = "${aws_lambda_function.acme_dns_route53.arn}"
}

# Give CloudWatch permission to invoke the function
resource "aws_lambda_permission" "permission" {
  action        = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.acme_dns_route53.function_name}"
  principal     = "events.amazonaws.com"
  source_arn    = "${aws_cloudwatch_event_rule.acme_dns_route53_sheduler.arn}"
}

์ด์ œ SSL ์ธ์ฆ์„œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๊ตฌ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€