Github Actionsで使用するAWSのクレデンシャルをGithub Appsで安全にキーローテーションする

プライベートのAWSアカウントをGithub Actions上のTerraformで管理するようにしました。 その過程でIAMユーザーのクレデンシャルをGithubのSecretsに保存しつつ、安全にキーローテションする方法をGithub Actionsで実装しました。

Github ActionsでAWSのキーローテーションをする場合はRotate AWS Access Keysが有名です。

READMEでも触れられているように、Github Actionsで使える GITHUB_TOKEN にはSecretsを更新する権限が付与されていません。Personal Access Tokenを発行してセットする方法が推奨されていますが、このトークンはアカウントがアクセス可能なすべてのリポジトリに権限を付与してしまうため安全ではありません。

今回はPersonal Access Tokenの替わりに専用のGithub Appsを作成し、特定のリポジトリだけにインストールすることで 安全にSecretsを更新できるようにしました。

Github Appsを作成する

まずはCreating a GitHub Appを参考に作成します。

作成できたら、Appの設定画面から秘密鍵を生成し、App IDを控えます。

作成したAppはInstalling GitHub Appsを参考に、このAppで管理したいリポジトリへインストールします。

インストールできたら、リポジトリの “Settings” - “Integration” からインストール済みAppの設定画面へ移動します。この時のURL https://github.com/settings/installations/XXXXXXXXXX の部分が Installation ID になるので、これを控えます。

ここで得た値をリポジトリのSecretsへ設定します。

Github Actionsを作成する

あとはいつも通り .github/workflows/aws_key_rotate.yml としてActionsをインストールします。

例:

Github Appsの GITHUB_TOKEN を取得する処理は拙作のnabeken/go-github-appsのGithub Actionsで処理しています。

これで、毎週月曜日の日本時間9時に自動的にキーが更新されるようになりました。 動作確認時または即時更新したい場合は actions/aws_key_rotate ブランチにpushしてください。

2021/02/21更新:

Gistの例で kneemaa/github-action-rotate-aws-secrets@v1.0.3 に渡すAWSのクレデンシャルをIAM userからローテーション用のIAM roleに変更しました。

万が一アクションに悪意のあるコードが混入された場合、IAM userが持つ権限あるいはAssume Role先の権限への昇格を許してしまうための対策です。

ローテーション用のIAM roleの例(Terraform):

resource "aws_iam_role" "key-rotate" {
  name = "example-key-rotate-role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Effect": "Allow",
          "Principal": { "AWS": "${var.deployment_user_arn}" },
          "Action": [
            "sts:AssumeRole",
            "sts:TagSession"
          ]
      }
  ]
}
EOF
}

resource "aws_iam_role_policy" "iam" {
  name = "key-rotation"
  role = aws_iam_role.key-rotate.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "iam:CreateAccessKey",
          "iam:DeleteAccessKey",
          "iam:GetUser",
          "iam:ListAccessKeys",
        ]
        Effect   = "Allow"
        Resource = var.deployment_user_arn
      },
    ]
  })
}