AWS KMS の encrypt API を使って、パスワード管理を行う
AWS KMSとは?
暗号化操作に使用されるキーを作成、管理することができるAWSのマネージドサービスです。
今回したいこと
DBのパスワードなど低容量のデータを暗号化したいのでカスタマーデータキー(CDK)を作成せず、KMSのencrypt APIを使ってカスタマーマスターキー(CMK)から暗号化を行います。
AWS CLI ドキュメント => https://awscli.amazonaws.com/v2/documentation/api/latest/reference/kms/index.html
事前準備
AWSコンソールからCustomer Managed Key(CMK)を作成し、キーID or alias を取得
- KMSの画面へ移り、左ペインからカスタマー管理型のキーを選択
- キーの作成を押下
- 今回はデフォルトのまま画面に従って進みます、aliasは「sample/key」としておきます
- 管理、使用アクセス許可ではUserかRoleを指定して設定します
- 生成されたキーポリシーを確認して問題なければ完了、CMKが作成されキーID or alias を取得できるようになります
CloudShellを使いAWS CLIを操作する
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を立ち上げます
まずは、暗号化、復号化の動作を確認していきます
暗号化したい文字列をplaintext.txtに保存します
$ echo 'password' >> plaintext.txt
encrypt APIで文字列の入ったファイルを指定し暗号化、CiphertextBlobの項目はbase64 encodeされた形式で出力されるのでこれをdecodeし、結果をencrypted.txtに保存
$ aws kms encrypt --key-id < CMK の KEY 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 < CMK の KEY 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 などを利用する運用などもありますが、手間や費用などを考えて最適な構成を選択していければよいと思います!