この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
コンニチハ、千葉です。
はじめに
複数チームで利用していくと、たくさん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 Cross 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を利用して複数のアカウントに展開しましょう。
https://dev.classmethod.jp/cloud/aws/introducing-cloudformation-stacksets/
管理対象のCFn
AWSTemplateFormatVersion: '2010-09-09'
Description: This CloudFormation template to create Cross 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 (Cross 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 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というアカウント間でリソースを共有できるサービスがでたので、こちらのアップデートに期待です。