AWS KMS の encrypt API を使って、パスワード管理を行う

#AWS CLI
#KMS

暗号化操作に使用されるキーを作成、管理することができるAWSのマネージドサービスです。

DBのパスワードなど低容量のデータを暗号化したいのでカスタマーデータキー(CDK)を作成せず、KMSのencrypt APIを使ってカスタマーマスターキー(CMK)から暗号化を行います。

 

AWS CLI ドキュメント => https://awscli.amazonaws.com/v2/documentation/api/latest/reference/kms/index.html

  • KMSの画面へ移り、左ペインからカスタマー管理型のキーを選択
  • キーの作成を押下
  • 今回はデフォルトのまま画面に従って進みます、aliasは「sample/key」としておきます
  • 管理、使用アクセス許可ではUserかRoleを指定して設定します
  • 生成されたキーポリシーを確認して問題なければ完了、CMKが作成されキーID or alias を取得できるようになります

CloudShellを使用することでアカウントのPermissionを持った状態ですぐにAWS CLIを叩くことができます

CloudShellのAWS CLIのバージョンは以下でした

$ aws --version aws-cli/2.8.12 Python/3.9.11 Linux/4.14.294-220.533.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2 prompt/off

 

以下の図のアイコンを押下してCloudShellを立ち上げます CloudShellリンク

 

まずは、暗号化、復号化の動作を確認していきます

暗号化したい文字列をplaintext.txtに保存します

$ echo 'password' >> plaintext.txt

 

encrypt APIで文字列の入ったファイルを指定し暗号化、CiphertextBlobの項目はbase64 encodeされた形式で出力されるのでこれをdecodeし、結果をencrypted.txtに保存

$ aws kms encrypt --key-id < CMKKEY ID > or < "alias/" + CMK の alias名 > \ --plaintext fileb://plaintext.txt \ --output text \ --query CiphertextBlob | base64 --decode > encrypted.txt

 

decrypt APIで復号化する場合は暗号化情報の入ったファイルだけを指定してPlaintextで取得、base64 encodeされているのでdecodeを行い、decoded-plain.txtに保存。中身を確認すると'password'が保存されています

ここで key-id を指定しないのは CiphertextBlob に key-id などのメタデータが含まれているからのようです

$ aws kms decrypt \ --ciphertext-blob fileb://encrypted.txt \ --output text \ --region ap-northeast-1 \ --query Plaintext | base64 --decode > decoded-plain.txt

以下はLambdaなどの環境変数に CiphertextBlob を保存し、DB接続に使用する例です

encrypt API コマンドの返り値の CiphertextBlob から base64 encode されている値を取得

$ aws kms encrypt --key-id < CMKKEY ID > or < "alias/" + CMK の alias名 > \ --plaintext fileb://plaintext.txt \ --output json >> { "CiphertextBlob": "xxxxxxxx", "KeyId": "arn:aws:kms:ap-northeast-1:xxxxxxx:key/xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx", "EncryptionAlgorithm": "SYMMETRIC_DEFAULT" }

 

PythonのSDKで以下のように復号化し、passwordを取得、DBへ接続する

import base64 import boto3 import os import psycopg2 kms_client = boto3.client('kms') class EstablishPgsqlConnection: @staticmethod def decrypt_kms_key(ciphertext_blob: str) -> str: try: res = kms_client.decrypt( CiphertextBlob=bytes(base64.b64decode(ciphertext_blob)) )['Plaintext'].decode('utf-8') return res except Exception as e: raise e @classmethod def establish_pgsql_connection(cls): connector = psycopg2.connect( 'postgresql://{user}:{password}@{host}:{port}/{dbname}'.format( user=os.environ.get('DB_USER'), password=cls.decrypt_kms_key(os.environ.get('CiphertextBlob')), host=os.environ.get('DB_HOST'), port=os.environ.get('DB_PORT'), dbname='dbname' ) ) return connector

今回はKMSを使いDBのpasswordを運用する手順を紹介しました

他にもSSMのPatameter Store の SercureString などを利用する運用などもありますが、手間や費用などを考えて最適な構成を選択していければよいと思います!