CloudFormationでIAMアクセスキーの発行とSecrets Managerへの格納をしてみた
こんにちは、CX事業本部 IoT事業部の若槻です。
今回は、CloudFormationでIAMアクセスキーの発行とSecrets Managerへの格納をしてみました。
なぜCloudFormationとSecrets Managerなのか?
(主観ですが)AWSのIaC機能は下記の2つです。
また、AWSのセキュアなパラメータ管理機能は主に下記の2つです。
- AWS Systems Manager Parameter Store(SecureStringを使用)
- AWS Secrets Manager
このうち、IAMアクセスキーの発行とそのクレデンシャルの格納をIaCで完結させられる方法は、調べてみたところ「CloudFormationとSecrets Managerの組み合わせのみ」だったため、今回その方法についてご紹介します。また記事後半では、その他の組み合わせがなぜ出来なかったかについても記載します。
やってみた
CloudFormation テンプレート
IAMユーザー作成、アクセスキー発行、Secrets Managerへの格納という検証に必要な最低限のリソース定義です。
AWSTemplateFormatVersion: '2010-09-09' Resources: IAMUser1: Type: AWS::IAM::User Properties: Path: / UserName: IAMUser1 IAMUser1AccessKey: Type: AWS::IAM::AccessKey Properties: UserName: !Ref IAMUser1 IAMUser1AccessKeySecret: Type: AWS::SecretsManager::Secret Properties: Name: !Sub ${IAMUser1}-credentials SecretString: !Sub "{\"accessKeyId\":\"${IAMUser1AccessKey}\",\"secretAccessKey\":\"${IAMUser1AccessKey.SecretAccessKey}\"}"
デプロイします。
% aws cloudformation deploy \ --template-file template.yaml \ --stack-name access-key-to-secret-stack \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
Secrets Manager に格納されたクレデンシャルの確認
AWSマネジメントコンソールでAWS Secrets Manager > シークレットより作成されたシークレットを見てみると、発行したIAMアクセスキーのIDとシークレットが格納されているのが確認できます。
その他の組み合わせ
いずれも仕様の制限により出来ませんでした。
AWS CDK と Secrets Manager
CloudFormationでは任意の値をSecrets Managerに格納できましたが、AWS CDKではSecrets Managerが自動生成した値しか格納できません。ドキュメントから抜粋の下記コードのようにgenerateSecretString
は使えますが、SecretString
は使えない制限があるようです。
// Default secret const secret = new secretsmanager.Secret(this, 'Secret'); secret.grantRead(role); new iam.User(this, 'User', { password: secret.secretValue, }); // Templated secret const templatedSecret = new secretsmanager.Secret(this, 'TemplatedSecret', { generateSecretString: { secretStringTemplate: JSON.stringify({ username: 'user' }), generateStringKey: 'password', }, }); new iam.User(this, 'OtherUser', { userName: templatedSecret.secretValueFromJson('username').toString(), password: templatedSecret.secretValueFromJson('password'), });
この制限については下記のIssueでも取り沙汰されています。もともとはセキュリティを考慮した制限であったようですが、それが必要な制限であるかの議論が交わされており、Amazonの中の人もフィードバックとして受け取っているようなので、今後の展開を注視したいと思います。
AWS CDK (CloudFormation) と Parameter Store
下記はIAMアクセスキーを発行し、そのクレデンシャルをParameter StoreにSecureString形式で格納するCDKコードです。
import * as cdk from "@aws-cdk/core"; import * as iam from "@aws-cdk/aws-iam"; import { StringParameter, ParameterType } from "@aws-cdk/aws-ssm"; export class SampleAppStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const operationUser = new iam.User(this, "operation_user"); const accessKey = new iam.CfnAccessKey(this, "access_key", { userName: operationUser.userName, }); const accessKeyId = accessKey.ref; const secretAccessKey = accessKey.attrSecretAccessKey; //アクセスキーIDをパラメータストアに格納 new StringParameter(this, "access_key_id_string_parameter", { parameterName: "access-key-id", stringValue: accessKeyId, type: ParameterType.SECURE_STRING, }); //シークレットアクセスキーをパラメータストアに格納 new StringParameter(this, "secret_access_key_string_parameter", { parameterName: "secret-access-key", stringValue: secretAccessKey, type: ParameterType.SECURE_STRING, }); } }
しかしこれをCDKデプロイするとエラーとなってしまいます。SecureString形式ではAWS CDK(CloudFormation)を使用して値を格納できないようです。
% cdk deploy SampleAppStack: deploying... SampleAppStack: creating CloudFormation changeset... 10:47:01 PM | UPDATE_FAILED | AWS::SSM::Parameter | accesskeyidstringparameter35E68FEF SSM Parameters of type SecureString cannot be created using CloudFormation
ちなみに平文のStringであればAWS CDKからでも格納はできますが、機密情報を暗号化せずに管理することになるのでそれは避けたいです。下記ドキュメントでもSecureString以外での機密情報の管理は非推奨と明記されています。
String パラメータまたは StringList パラメータに機密データを保存しないでください。機密データを暗号化したままにする場合は、SecureString パラメータタイプのみを使用します。
参考
- AWS::IAM::AccessKey -
- AWS::SecretsManager::Secret -
- AWS CLIからCloudFormation でユーザとロールを作成して、流れるようにスイッチロールの確認をしてみた | DevelopersIO
以上