AWS Config Rulesをアカウント間で共有しつつ、たくさんのアカウントに自動で展開する
コンニチハ、千葉です。
はじめに
複数チームで利用していくと、たくさんAWSアカウントが増えて、セキュリティやガバナンス、コンプライアンスを守るために中央管理で頑張り、ボトルネックになっていくことがあります。しかし、AWSでは自動化ができるので、チームに権限を委譲したうえでセキュリティ、ガバナンス、コンプライアンスを構築する土台があります。ブロッカーではなく、ガードレールが作れると幸せな世界が築けそうです。
ってことで、AWSにはConfig Rulesというサービスがあり、こちらを導入すると意図しない設定が入っているリソースを可視化したり、通知したりすることができます。 今回は、マルチアカウント環境でConfig Rulesを共有し、かつ自動で複数アカウントに展開してみました。これで、どれだけアカウントが増えようともへっちゃらです。
やってみた
全体イメージサマリ
Config Rulesを管理するアカウントを管理アカウント、ルールを利用するアカウントを管理対象アカウントとします。 動作イメージはこちら。
設定イメージはこちら。
管理アカウントでやること
- Lambda実行用のIAMロール作成(STS、CWLogs,config:PutEvaluations)
- Lambda関数の作成
- STSで管理対象の一時クレデンシャルを取得
- 任意の処理を実行
- 評価結果をputする
- Lambda関数にクロスアカウント Configからの実行許可を付与(add permission)
管理対象アカウントでやること
- AWS Config Rules用のIAMロールを作成
- 付与する権限:SecurityAudit
- 信頼関係:AWS Config, 管理アカウントのIAMロール
- AWS Config Rulesの作成
- 管理アカウントのLambda ARNを指定
やってみた
いやー、やること整理するだけでかなり大変でした。すごく複雑です。そのため簡単に実装できるようにCFn化しました。
前提
前提として管理対象アカウントでConfigを有効にしておきます。
管理アカウントでやること
CloudFormationを貼っておきます。事前にLambdaのコードはzipでS3へアップロードしてください。 Config Rules用のコードはawslabs/aws-config-rulesに色々いあるので参考にしたり、コピーしてそのまま使いましょう。コード利用時の注意事項としては、ASSUME_ROLE_MODE という項目があるのでTrueにします。そうすると、STSを利用して一時クレデンシャルを取得するようになるので、クロスアカウントで利用可能になります。
管理アカウント用のCFn
AWSTemplateFormatVersion: '2010-09-09' Description: This CloudFormation template to create Crross Account Config Rules for Admin Account. Parameters: Environment: Description: Type of this environment. Type: String Default: stg AllowedValues: - prd - stg - dev SystemName: Description: Name of this system. Type: String Default: web LambdaFunctionS3Bucket: Description: S3 bucket name Type: String Default: s3-bucket-name-your-lambda-function LambdaFunctionS3Key: Description: S3 key Type: String Default: xx/xx.zip LambdaInvokeCrossAccount: Description: Cross AWS Account ID Type: String Default: 111111111111 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Environment Configuration Parameters: - SystemName - Environment - Label: default: Lambda Function Parameters: - LambdaFunctionS3Bucket - LambdaFunctionS3Key Resources: # Lambda Function LambdaFunctionIAMCheck: Type: "AWS::Lambda::Function" Properties: Handler: "lambda_function.lambda_handler" Role: Fn::GetAtt: - "LambdaExecRole" - "Arn" Code: S3Bucket: !Sub ${LambdaFunctionS3Bucket} S3Key: !Sub ${LambdaFunctionS3Key} Runtime: "python3.6" Timeout: "60" # Lambda Function add execute permission from config rules of managed account LambdaPermission: Type: AWS::Lambda::Permission Properties: Action: "lambda:InvokeFunction" FunctionName: !GetAtt - LambdaFunctionIAMCheck - Arn Principal: "config.amazonaws.com" SourceAccount: !Sub ${LambdaInvokeCrossAccount} # IAM Role LambdaExecRole: Type: AWS::IAM::Role Properties: RoleName: !Sub role-${Environment}-${SystemName}-lambda ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSConfigRole - arn:aws:iam::aws:policy/SecurityAudit Path: / AssumeRolePolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } # IAM Policy LambdaExecPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Sub policy-${Environment}-${SystemName}-lambda Description: !Sub policy-${Environment}-${SystemName}-lambda PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "config:PutEvaluations" ], "Resource": [ "*" ] }, { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "sts:AssumeRole" ], "Resource": "*" } ] } Roles: - !Ref LambdaExecRole
Lambdaのコード
Assume Roleで、一時クレデンシャルを取得するコードを入れておきます。GitHubにあるAWSラボのコードをみたのですが、管理対象アカウントのConfigロールに対してAssume Roleしていました。今回は、以下のようにして作成したRoleにAssume Roleするようなコードを入れました。(AWSラボのコードを利用する場合は、クレデンシャル取得する箇所を以下に変更しましょう。自分で一からカスタムルール作成するときは、このコードを埋め込みましょう。
executionRoleArn = 'arn:aws:iam::' + event["accountId"] + ':role/role-exec-config-rules' credentials = get_assume_role_credentials(executionRoleArn) return boto3.client(service, aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'] )
管理対象アカウントでやること
入力には、管理アカウントのLambdaに指定しているIAMロールARN、LambdaのARNが必要になりますので取得しておきましょう。 こちらのCFnをStacSetsを利用して複数のアカウントに展開しましょう。
管理対象のCFn
AWSTemplateFormatVersion: '2010-09-09' Description: This CloudFormation template to create Crross Account Config Rules for Managed Account. Parameters: Environment: Description: Type of this environment. Type: String Default: stg AllowedValues: - prd - stg - dev SystemName: Description: Name of this system. Type: String Default: web AllowAccessRole: Description: Role of Lambda on Cross Account(ARN) Type: String Default: Role on Admin Account ConfigRulesLambda: Description: Lambda for ConfigRules(Crros Account Lambda ARN) Type: String Default: Cross Account Lambda ARN Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Environment Configuration Parameters: - SystemName - Environment - Label: default: Config Configure Parameters: - ConfigRulesLambda - AllowAccessRole Resources: # Config Setting # ConfigRecorder: # Type: AWS::Config::ConfigurationRecorder # Properties: # Name: default # RecordingGroup: # ResourceTypes: # - "AWS::IAM::User" # RoleARN: # Fn::GetAtt: # - ConfigRole # - Arn # Config Rules ConfigRuleIAMNoUser: Type: AWS::Config::ConfigRule Properties: ConfigRuleName: "ConfigRuleIAM_NO_USER" Description: "IAM NO USER" InputParameters: tag1Key: test1 Scope: ComplianceResourceTypes: - "AWS::IAM::User" Source: Owner: "CUSTOM_LAMBDA" SourceIdentifier: !Sub ${ConfigRulesLambda} SourceDetails: - EventSource: "aws.config" MessageType: "ConfigurationItemChangeNotification" # IAM Role ConfigRole: Type: AWS::IAM::Role Properties: RoleName: !Sub role-exec-config-rules ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSConfigRole - arn:aws:iam::aws:policy/SecurityAudit Path: / AssumeRolePolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "${AllowAccessRole}" }, "Action": "sts:AssumeRole" }, { "Effect": "Allow", "Principal": { "Service": "config.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } # IAM Policy LambdaExecPolicy: Type: AWS::IAM::ManagedPolicy Properties: ManagedPolicyName: !Sub policy-${Environment}-${SystemName}-lambda Description: !Sub policy-${Environment}-${SystemName}-lambda PolicyDocument: !Sub | { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "config:PutEvaluations" ], "Resource": [ "*" ] } ] } Roles: - !Ref ConfigRole
管理対象アカウントから評価を実行
管理対象から評価を実施し、結果が表示されるかやってみました。
表示できました!
最後に
かなり複雑で、はまって検証時間がかかりました。クロスアカウントはやっぱりむずかしいですね。CFn化したので、ある程度簡略化できましたが。最近Resource Access Managerというアカウント間でリソースを共有できるサービスがでたので、こちらのアップデートに期待です。