Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

Amazon AuroraのMySQLユーザーをTerraformで安全に管理したい

SREの菅原(id:ksugahara08)です。

最近、既存のシステムをAmazon Auroraへ移行させるという作業が頻繁に発生しました。

モテ期かな?と勘違いするくらいAuroraに関しての仕事に恵まれたため、その中でも役に立ったTerraformでAmazon AuroraのMySQLユーザーを管理する方法を今回紹介します。

興味あれば最後まで読んで頂けると幸いです。

目次

Terraformでのパスワード管理の難しさ

どのように設定したかお話する前にTerraformでのパスワード管理の難しさについて少しだけ触れておきたいと思います。

Terraformでパスワードを隠すにはtfファイルだけでなく、tfstateファイルにも気を付けなければいけません。tfstateファイルは外部に漏れないように厳重に管理していても、漏れてしまう可能性は拭いきれません。したがって、tfファイルとtfstateファイルの両方に平文で保存されないことを考えなければいけないという難しさがあります。

鍵の暗号化・復号化

いくつか手段があったのですが今回はTerraformとAWS Key Management Service (KMS)を使った暗号・復号化を選択しました。

具体的にはTerraformのaws_kms_secretsとKMSのaws kms encryptで平文をカスタマーマスターキーから直接暗号化する方法を組み合わせました。この組み合わせであればtfstateファイルにもパスワー ドが平文保存されなかったため採用しました。

GPG鍵を使った方法も実装してみたのですが、マスターキーを自分で保管しなくて良いという点でKMSの方を選びました。またHashiCorp社のVaultをTerraformと組み合わせれば良いかなと調べてみたのですが、tfstateファイルには平文で保存されてしまうという記事を読み、Vaultは選択肢から外しました。

Terraformでの設定

本題のTerraformの実装方法について話していきます。

AWS Key Management Service (KMS) のマスターキーを作成

まず、KMSのCustumer Master Keyを作成します。kms.tfは設定例です。

kms.tf

resource "aws_kms_key" "sample" {
  description             = "Custumer Master Key"
  enable_key_rotation     = true
  is_enabled              = true
  deletion_window_in_days = 30
}

resource "aws_kms_alias" "sample" {
  name          = "alias/sample"
  target_key_id = aws_kms_key.sample.key_id
}

AWSのKMS権限を設定したIAMを作成

AWSのEC2インスタンスを使っているのであればIAMロールを作成して割り当てます。そうでなければIAMユーザーを作成します。

IAMポリシーは以下のようなものを設定していれば暗号化・復号化ができます。(詳しくはAWSの公式ドキュメントに書いてあるので各自調整してください。)

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": [
      "kms:Encrypt",
      "kms:Decrypt"
    ],
    "Resource": [
      "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab",
      "arn:aws:kms:us-west-2:111122223333:key/0987dcba-09fe-87dc-65ba-ab0987654321"
    ]
  }
}

KMSを使ってパスワードを暗号化

aws kmsコマンドで暗号化します。 先程作ったIAMロールかIAMユーザーを使用して以下を実行します。

$ vim secret.txt
# 暗号化したいパスワードや文字列を書き込みます。

$ aws kms encrypt \
    --key-id alias/sample \
    --plaintext fileb:///path/to/secret.txt \
    --query CiphertextBlob \
    --output text
# ここで出力された文字列をTerraformのtfファイルに記載します。

$ rm secret.txt
# 暗号化できたらファイルは廃棄します。

この手順でAuroraのrootユーザー名、rootパスワード、作成したいユーザーのパスワード等を暗号化しておきます。

MySQLユーザーの設定

以下のmysql_users.tfを使ってAmazon Auroraに接続して、MySQLユーザーを作成します。 このときTerraformが使っているIAMにRDSへの接続権限と接続できるNWで実行する必要があります。

mysql_users.tf

data "aws_kms_secrets" "sample_aurora" {
  secret {
    name    = "root_username"
    payload = "暗号化のときに受け取った文字列"
  }
  secret {
    name    = "root_password"
    payload = "暗号化のときに受け取った文字列"
  }
  secret {
    name    = "sample_password"
    payload = "暗号化のときに受け取った文字列"
  }
}

# Amazon Auroraへの接続はここで行っています。
provider "mysql" {
  endpoint = "sample-cluster.cluster-XXXXXXXX.ap-northeast-1.rds.amazonaws.com"
  username = data.aws_kms_secrets.sample_aurora.plaintext["root_username"]
  password = data.aws_kms_secrets.sample_aurora.plaintext["root_password"]
}

resource "mysql_user" "sample" {
  user  = "sample"
  host  = "%"
  plaintext_password = data.aws_kms_secrets.sample_aurora.plaintext["sample_password"]
}

resource "mysql_grant" "sample" {
  user       = mysql_user.sample.user
  host       = mysql_user.sample.host
  database   = "sample"
  table      = "*"
  privileges = ["SELECT", "INSERT", "UPDATE", "DELETE"]
}

plaintext_passwordで設定すればtfstateファイルにはハッシュ化された値だけが入ります。terraform state show mysql_user.sampleterraform state pullコマンドを使えば、パスワードが見えないことを確認できます。

Auroraへの接続はprovider mysqlを使って行うのですが、KMSを組み合わせることでパスワードを平文で書かずに済みます。

KMSを使ってパスワードを復号化

後からMySQLのパスワードを知りたい場合は以下のコマンドで復号して確認することができます。

$ aws kms decrypt \
    --ciphertext-blob fileb://<(echo '暗号化のときに受け取った文字列'|base64 -d) | jq .Plaintext \
    --raw-output |base64 -d

あとがき

今まではAnsible Vault機能を使ってパスワードを保持していたのですが、今回の方法でtfファイルにもtfstateファイルにも平文で持たなくて済みました。また復号するための鍵を手元ではなくKMSに保管することができたのでかなりメリットがありました。

課題としてはKMSの復号化ができるIAMユーザーの取り扱いには注意が必要だということです。IAMユーザーが漏れると復号化ができてしまう可能性があるからです。

まだまだパスワードや鍵の管理には頭を悩ませることもありますが少しずつ改善していきたいと思います。