dehio3’s diary

仕事、生活、趣味のメモ

lego(Let’s Encryptクライアント)利用時に、他のAWSアカウントのRoute53を自動更新させるためのIAMロールの作成方法

f:id:dehio3:20190710094851p:plain

はじめに

AWS環境にてSSL証明書としてLet’s Encryptを利用しており、Let’s Encryptクライアントとしてlegoを使用した場合、legoが動作しているEC2インスタンスからRoute53のPublicレコードを制御可能にさせる必要がある。

EC2に設定するポリシーは以下を参照

github.com

legoを動かしているAWSアカウントと別のAWSアカウントで、Route53のPublicレコードを管理している場合に、クロスアカウントアクセスのIAMロールを作成する方法です。

前提条件

  • terraformにてIAMロールを作成する
  • アカウントA:Route53のPublicレコードを管理しているAWSアカウント
  • アカウントB: legoが動作するEC2インスタンスが存在するAWSアカウント

terraform

アカウントAで作成するIAMロール

aws_iam_role

Principal には接続元となるlego動作するAWSアカウントを設定

resource "aws_iam_role" "letsencrypt-cross-acount-role" {
    name               = "letsencrypt-cross-acount-role"
    path               = "/"
    assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<BのAWSアカウントID>:root"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
      }
    }
  ]
}
POLICY
}

aws_iam_policy_document

こちらのポリシーをそのまま

data "aws_iam_policy_document" "letsencrypt-cross-acount-policy" {
  statement {
    effect  = "Allow"
    actions = [
      "route53:GetChange",
      "route53:ChangeResourceRecordSets",
      "route53:ListResourceRecordSets",
    ]
    resources = [
      "arn:aws:route53:::hostedzone/*",
      "arn:aws:route53:::change/*"
    ]
  }
  statement {
    effect  = "Allow"
    actions = [
      "route53:ListHostedZonesByName",
    ]
    resources = [
      "*"
    ]
  }
}

aws_iam_role_policy

作成したロールにポリシーをアタッチ

resource "aws_iam_role_policy" "letsencrypt-cross-acount-policy" {
  name    = "letsencrypt-cross-acount-policy"
  role    = "${aws_iam_role.letsencrypt-cross-acount-role.id}"
  policy  = "${data.aws_iam_policy_document.letsencrypt-cross-acount-policy.json}"
}

アカウントBで作成するIAMロール

aws_iam_role

EC2に割り当てるロール

resource "aws_iam_role" "iam_role_instance" {
  name = "iam_role_instance"
  path = "/"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_instance_profile" "iam_instance_profile" {
  name = "instance-role"
  role = "${aws_iam_role.iam_role_instance.name}"
}

aws_iam_policy_document

アカウントAと同様にこちらのポリシーと、アカウントAに作成したロールのarn情報を設定

data "aws_iam_policy_document" "letsencrypt-cert-policy" {
  statement {
    effect  = "Allow"
    actions = [
      "route53:GetChange",
      "route53:ChangeResourceRecordSets",
      "route53:ListResourceRecordSets",
    ]
    resources = [
      "arn:aws:route53:::hostedzone/*",
      "arn:aws:route53:::change/*"
    ]
  }
  statement {
    effect  = "Allow"
    actions = [
      "route53:ListHostedZonesByName",
    ]
    resources = [
      "*"
    ]
  }
  statement {
    effect  = "Allow"
    actions = [
      "sts:AssumeRole",
    ]
    resources = [
      "arn:aws:iam::<AのAWSアカウントID>:role/letsencrypt-cross-acount-role"
    ]
  }
}

aws_iam_role_policy

resource "aws_iam_role_policy" "instance_role_policy" {
  name    = "instance_role_policy"
  role    = "${aws_iam_role.iam_role_instance.id}"
  policy  = "${data.aws_iam_policy_document.letsencrypt-cert-policy.json}"
}

動作確認

legoを動作させるEC2インスタンスにIAMロールを設定後、以下のコマンドでZone情報が取れる事を確認する

aws route53 list-hosted-zones-by-name --hosted-zone-id <Zone ID>

参考

IAMロール徹底理解 〜 AssumeRoleの正体 | DevelopersIO

AssumeRoleを使って他のロールの情報を取得する方法 | ハックノート

追記

そもそもDNS認証だと、同一アカウント内にRoute53レコードが必要かも・・

上記の確認コマンドの様にZoneIDを指定すれば他のアカウントの情報取れるけど、legoコマンド実行するときはドメイン名しか指定しない。

ドメイン名からZoneIDを取得しようとすると、自アカウント内で検索して、ZoneIDがヒットしない気が・・

$ aws route53 list-hosted-zones-by-name --dns-name <FQDN>
{    "HostedZones": [], 
    "DNSName": "<FQDN>", 
    "IsTruncated": false, 
    "MaxItems": "100"
}