cdkのsolution constructを利用してみた
cdkのsolution constructが便利だったのでブログに書いてみます。
solution constructとは
AWSの公式ドキュメントに説明がありました。
aws.amazon.com
AWS Solutions Constructs は、2 つ以上の CDK のリソースを組み合わせ、ロギングや暗号化などのベストプラクティスを実装する複数サービスのパターンを提供します。
要はよくあるパターンをAWSが準備してくれているということですね。
本記事で利用したもの
今回はaws-events-rule-snsを利用してみました。
docs.aws.amazon.com
こちらのイメージ図は下記です。
よくある構成です。
動かしてみる
下記のようにソースをサンプルで書いてみました。
enableEncryptionWithCustomerManagedKeyをfalseにしておくと
kmsをデフォルトキーで利用してくれます。
(私は最初こちらを指定していなくて無駄なkmsを作成してしまいました)
フォルダ構成イメージ
lib └── aws-events-rule-sns-stack.ts patterns ├── SecurityhubNotify.ts └── index.ts
aws-events-rule-sns-stack.ts
import * as cdk from '@aws-cdk/core'; import { EventsRuleToSnsProps, EventsRuleToSns } from "@aws-solutions-constructs/aws-events-rule-sns"; import * as patterns from '../patterns/index' export class AwsEventsRuleSnsStack extends cdk.Stack { public readonly constructStack: EventsRuleToSns; constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const patternToNotify = patterns[patterns.patternName] const envcode = new cdk.CfnParameter(this, "envcode", { type: "String", description: "envcode", default:"test" }); const constructStack = new EventsRuleToSns(this, 'eveSns', { eventRuleProps: { eventPattern: patternToNotify, ruleName: `${envcode.valueAsString}-${patterns.patternName}` }, topicProps:{ topicName:`${envcode.valueAsString}-${patterns.patternName}` }, enableEncryptionWithCustomerManagedKey: false }); this.constructStack=constructStack } }
index.ts
export { SecurityhubNotify } from "./SecurityhubNotify"; export const patternName='SecurityhubNotify' ;
SecurityhubNotify.ts
export const SecurityhubNotify={ "source": ["aws.securityhub"], "detail-type": ["Security Hub Findings - Imported"], "detail": { "findings": { "Compliance": { "Status": ["FAILED", "WARNING", "NOT_AVAILABLE"] } } } }
package.json(関連部分のみ抜粋しています)
"dependencies": { "@aws-cdk/core": "^1.114.0", "@aws-solutions-constructs/aws-events-rule-sns": "^1.114.0", "source-map-support": "^0.5.19" },
deployとリソース確認
deployします
cdk deploy --parameters envcode=test
events+snsとsnsポリシーが作成されています。
ポリシーも良い感じでeventsへの許可が記載されています。
{ "Sid": "2", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "arn:aws:sns:ap-northeast-1:xxxxxx:test-SecurityhubNotify" }
触ってみて
感覚的にはeventsのフィルター部分だけ書けば、
events + snsを作成してくれるので便利でした。
他にもlambdaやs3等を絡めたパターンもあるようなので
機会があれば触ってみようと思います。
SAMでgithub actionsを利用する時にIAMユーザを払い出さないで利用したい
先日こちらでAWS SAMとgithub actionsの連携を試してみました。
上記利用する際に、IAMユーザとクレデンシャルを払い出す必要がありました。
ただ、諸事情によりIAMユーザを払い出さないで利用したいというケースがありました。
私の環境ではAWS SSOを利用していたため
AWS SSOで一時的なcredentialを取得し、
その一時的なcredentialをgitにsecretとして登録し、
SAMのdeployができないかと考え試してたところ
できたのでブログ化してみました。
設定方法
AWS SSOでcredentialを取得
まずはAWS SSOでcredentialを取得します。
これは、STS等を利用しても取得が可能ですが、
SSOを利用すると1クリックで取得可能なので便利です
上記の「click to... 」の箇所をクリックすればOKです
下記のようなクレデンシャルが取得できると思います。
export AWS_ACCESS_KEY_ID="xxxxxxxxxxx" export AWS_SECRET_ACCESS_KEY="xxxxxxxx" export AWS_SESSION_TOKEN="xxxxxxxxxxx"
そして取得した一時credentialを
githubのsecretとして設定します。
そのまま貼り付ければOKでした。
下記の例ではEXPORTSとして登録しています。
github actionsの設定ファイルを下記のように記載し
pushしたところ正常にdeployができました。
変化点は最後のsam deployのところで、SSOのcredentialを設定した上で、
sam deployを実行しています。
on: push: branches: - master env: stackName: aws-xxxxxxx s3BucketName: aws-xxxxxxxxx deployRegion: ap-southeast-1 jobs: build-deploy: runs-on: ubuntu-latest steps: - run: echo ${{ secrets.DOCKERHUB_TOKEN }} | docker login -u ${{ secrets.DOCKERHUB_USER }} --password-stdin - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.7' - uses: aws-actions/setup-sam@v1 # - uses: aws-actions/configure-aws-credentials@v1 # with: # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # aws-region: ap-northeast-1 # sam build - run: sam build --use-container # Run Unit tests- Specify unit tests here # - run : pip install -r requirements.txt # sam deploy - run: ${{ secrets.EXPORTS }} && sam deploy --no-confirm-changeset --no-fail-on-empty-changeset --stack-name ${{ env.stackName }} --s3-bucket ${{ env.s3BucketName }} --capabilities CAPABILITY_IAM --region ${{ env.deployRegion }}
使ってみて
上記は一時的なcredentialなので、時間が切れば権限が切れます。
デプロイする都度上記の設定するのは面倒ですが、
一時的なcredentialの時間制限は最大12時間なので、
一回払い出して設定すれば、その日ぐらいは使いまわせると思います。
たまにしか更新しないものであれば、払い出すIAMの管理も面倒だし、
このやり方も一つかなと思いました。
もっと良いやり方があるという方がいらっしゃたら教えて頂けますと嬉しいです。
AWS SAM がgithub actionsを使えるようになったので試してみた
AWS SAMがgithub actionsを利用できるようになったようなので使ってみました。
使ってみるとめちゃくちゃ良かったので、記事にしてみました。
事前準備
まず何でも良いのでsamを作成します
sam init -r python3.8 -n github-actions-with-aws-sam --app-template "hello-world"
続いて.github/workflows/sam-pipeline.ymlを追加します
※regionとs3バケットを書き換えてください
on: push: branches: - main jobs: build-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 - uses: aws-actions/setup-sam@v1 - uses: aws-actions/configure-aws-credentials@v1 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ##region## # sam build - run: sam build --use-container # Run Unit tests- Specify unit tests here # sam deploy - run: sam deploy --no-confirm-changeset --no-fail-on-empty-changeset --stack-name sam-hello-world --s3-bucket ##s3-bucket## --capabilities CAPABILITY_IAM --region ##region##
credentialの登録
githubのsettings > secretsで下記を登録します。
pushしてみる
上記で準備ができましたのでmainにpushしてみます
git add . git commit -m "add github actions" git push origin main
無事にactionsが完了しました。
APIGatewayが作成されていますので
実行してみるとレスポンスが返ってくることを確認できました。
curl -X GET https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello {"message": "hello world"}
変更してみる
さらに、lambdaを変更し、再度pushすると、
変更が反映されていることが確認できました。
cat hello_world/app.py import json # import requests def lambda_handler(event, context): return { "statusCode": 200, "body": json.dumps({ "message": "hello world update", # "location": ip.text.replace("\n", "") }), }
curl -X GET https://xxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello {"message": "hello world update"}
テスト(pytest)を実行してみる
pytest利用する場合も試してみました。
簡単にテストを書いてみます
cat tests/unit/test_handler.py import json import pytest from hello_world import app def test_lambda_handler(): ret = app.lambda_handler("", "") assert ret["statusCode"] == 200 def test_err_lambda_handler(): ret = app.lambda_handler("", "") assert ret["statusCode"] == 400
github actionsでpytest可能なよう設定します
cat requirements.txt pytest
.github/workflows/sam-pipeline.ymlにテスト部分を追記します
# sam build - run: sam build --use-container # Run Unit tests- Specify unit tests here - run : pip install -r requirements.txt # 追記 - run: pytest -s -k test_lambda_handler # 追記 # - run: pytest -s -k test_err_lambda_handler # 追記
pytestが実行されることが確認できました
上記のコメントアウトしていた失敗する方のテストケースも流してみます。 .github/workflows/sam-pipeline.ymlを修正します
# sam build - run: sam build --use-container # Run Unit tests- Specify unit tests here - run : pip install -r requirements.txt # 追記 - run: pytest -s -k test_lambda_handler # 追記 - run: pytest -s -k test_err_lambda_handler # 追記
きちんと失敗してくれていることが確認できました
失敗した場合は、後続の処理が行われず
デプロイがされずに止まってくれます。
最後に
個人的には今後samを利用するときは、
この使い方がベースになりそうなほど良かったです。
今回試してみたのの元ネタはこちらです。
細かい箇所はこちらも併せてご参考ください。
aws.amazon.com
AWS organizationsでcloudtrailを別Accountへ権限移譲する
AWS Organizationsの連携機能を色々と試しており、
cloudtrailでも連携機能を試してみました。
下記を参考にさせて頂いており、
KMSも含めて権限移譲をやろうとすると割と面倒で、
最終的にcloudformationを作成したのでブログ化してみました。
fu3ak1.hatenablog.com
Organizations とCloudtrail連携機能(AWS純正)
AWS Organizationsでは、Cloudtrailと連携し、
複数アカウントでのcloudtrail設定を簡単に実現できます。
cloudtrailで単純にorganizations連携をすると
下記のようになります。
上記でも十分にcloudtrailログを集約できるのですが
AWSのマルチアカウントのベストプラクティスでは、
ログ集約用の目的別のアカウント
(以下、LogArchiveアカウントと表現します)の別途作成を推奨しています。
要は何でもかんでも、親アカウントに集めるのは
権限が集約しすぎて良くないということですね。
上記理由から、純正機能でのcloudtrail集約をそのまま利用すると
ベストプラクティスに沿っていないのかと思いました。
aws.amazon.com
ベストプラクティス風にするには
LogArchiveアカウントを別にした構成を考えると
下記のように設定したいと考えました。
別途LogArchiveアカウントを作成し、
AdminAccountで収集したcloudtrailログを
LogArchiveアカウントに集約します。
上記、手動で設定しても良いですが、
割とポリシー系が面倒だったので、
cloudformationを作ってしてみました。
1.LogArchiveアカウントでの作業
まず、LogArchiveアカウントで、
S3とKMSを作成します。
LogArchiveアカウントで以下のcloudformationを適応します。
AWSTemplateFormatVersion: "2010-09-09" Description: A templete for Parameters: EnvPrefix: Type: String Default: OrgTrail orgAccountId: Type: String Default: xxxxxxxxxxxx Description: "Organization Admin Account Id" S3BucketName: Type: String Default: xxxxxxxxxxxxxxxxxxxxxxxxxx Description: "bucket name for cloudtrail" Resources: mykms: Type: AWS::KMS::Key Properties: Description: !Sub ${EnvPrefix}Key Enabled: true EnableKeyRotation: true KeyUsage: ENCRYPT_DECRYPT PendingWindowInDays: 30 KeyPolicy: Version: '2012-10-17' Id: key-policy Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub arn:aws:iam::${AWS::AccountId}:root Action: kms:* Resource: "*" - Sid: Allow use of the key Effect: Allow Principal: AWS: !Sub arn:aws:iam::${orgAccountId}:root Action: - kms:Encrypt - kms:Decrypt - kms:ReEncrypt* - kms:GenerateDataKey* - kms:DescribeKey Resource: "*" - Sid: Allow attachment of persistent resources Effect: Allow Principal: AWS: !Sub arn:aws:iam::${orgAccountId}:root Action: - kms:CreateGrant - kms:ListGrants - kms:RevokeGrant Resource: "*" Condition: Bool: kms:GrantIsForAWSResource: 'true' - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: - !Sub arn:aws:iam::${orgAccountId}:root Action: kms:* Resource: "*" - Sid: Allow CloudTrail to encrypt logs Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: kms:GenerateDataKey* Resource: "*" Condition: StringLike: 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub arn:aws:cloudtrail:*:${orgAccountId}:trail/* - Sid: Allow CloudTrail to describe key Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: kms:DescribeKey Resource: "*" - Sid: Allow principals in the account to decrypt log files Effect: Allow Principal: AWS: "*" Action: - kms:Decrypt - kms:ReEncryptFrom Resource: "*" Condition: StringEquals: kms:CallerAccount: !Ref orgAccountId StringLike: 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub arn:aws:cloudtrail:*:${orgAccountId}:trail/* - Sid: Allow alias creation during setup Effect: Allow Principal: AWS: "*" Action: kms:CreateAlias Resource: "*" Condition: StringEquals: kms:CallerAccount: !Ref orgAccountId kms:ViaService: ec2.us-east-1.amazonaws.com - Sid: Enable cross account log decryption Effect: Allow Principal: AWS: "*" Action: - kms:Decrypt - kms:ReEncryptFrom Resource: "*" Condition: StringEquals: kms:CallerAccount: !Ref orgAccountId StringLike: 'kms:EncryptionContext:aws:cloudtrail:arn': !Sub arn:aws:cloudtrail:*:${orgAccountId}:trail/* # Outputs: # Outputskmsid: # Description: kms-trail-organizations # Value: !GetAtt mykms.Arn # Export: # Name: !Sub ${EnvPrefix}-kms S3BucketOrg: Type: "AWS::S3::Bucket" Properties: BucketName: !Ref S3BucketName PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true S3BucketpublicdataBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref S3BucketOrg PolicyDocument: Statement: - Sid: AWSCloudTrailAclCheck Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: "s3:GetBucketAcl" Resource: !Sub arn:aws:s3:::${S3BucketName} - Sid: AWSCloudTrailWrite Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: 's3:PutObject' Resource: !Sub arn:aws:s3:::${S3BucketName}/AWSLogs/${orgAccountId}/* Condition: StringEquals: 's3:x-amz-acl': bucket-owner-full-control - Sid: AWSCloudTrailWriteMyaccount Effect: Allow Principal: Service: cloudtrail.amazonaws.com Action: 's3:PutObject' Resource: !Sub arn:aws:s3:::${S3BucketName}/AWSLogs/${AWS::AccountId}/* Condition: StringEquals: 's3:x-amz-acl': bucket-owner-full-control
2.AdminAccount(親アカウント)での作業
次にAdminAccount(organizationsの親アカウント)で、
cloudtrailを作成します。
この時、パラメータに上記で作成したLogArchiveアカウントの
S3の名前とKMSのidを設定します。
AdminAccountで以下のcloudformationを適応します。
AWSTemplateFormatVersion: "2010-09-09" Description: A templete for taf init Parameters: S3BucketName: Type: String Default: xxxxxxxxxxxxxxxxxx Description: "bucket name for cloudtrail. this is expected to be log Archive's account bucket name" kmsid: Type: String Default: 3e20a5ef-xxxxxxx-xxxx-xxxx Description: "kms-id in log Archive Account" AccountIdLog: Type: String Default: xxxxxxxxxx Description: "AWS Account Id of logArchive" Resources : mytrail: Type: AWS::CloudTrail::Trail Properties: # CloudWatchLogsLogGroupArn: String # CloudWatchLogsRoleArn: String EnableLogFileValidation: true # EventSelectors: # - EventSelector IncludeGlobalServiceEvents: true IsLogging: true IsMultiRegionTrail: true KMSKeyId: !Sub arn:aws:kms:us-east-1:${AccountIdLog}:key/${kmsid} S3BucketName: !Ref S3BucketName # S3KeyPrefix: String # SnsTopicName: String # Tags: # - Resource Tag TrailName: !Ref S3BucketName
cloudtrailをorganizations連携する
上記適応後に、AWSコンソールから作成されたcloudtrailを開き、
「Enable for all accounts in my organization」を有効化します。
cloudformationでは、この設定値が設定できなかったので、
ここだけ手動設定になります。
上記でベストプラクティス風の構成が実現できました。
さいごに
AWSでcloudtrailの権限移譲を構成してみました。
冒頭で紹介したブログは、cloudtrail以外にも、
Organiztions関連の連携まとめが記載されており分かりやすいです。
いつも参考にさせてもらっています。
ありがとうございます。
このブログもどなたか参考にして頂けると嬉しいです。
fu3ak1.hatenablog.com
AWS Control Towerのcloudformationを読み解いたので誰かに褒めてほしい
AWS Control Towerを触ってみた
Contorl Towerの東京リージョンがサポートされたので触ってみました。
色々と調査する過程で、Control Towerを有効化した時に
裏側で流れるcloudformationを読み解いて図示したので
きっと誰かの役に立つと思いブログ化してみました。
Control Towerを有効化する前
簡単に、有効化前はorganizationsの配下にたくさんアカウントがいると仮定します。
Control Towerを有効化した後
control towerを有効化しても、既存アカウントに即座には影響はありません。
control towerが有効化されているOUの配下にアカウントを持ってくると
各種設定(cloudformationやらSCPやら)が有効化されます。
ここで、SCPは分かりやすくドキュメントに整理されていました。 docs.aws.amazon.com
ただ、cloudformationの方は、分かりやすく記載されたものが
見つけられませんでした。
ドキュメントをみてみると、cloudformaitonを確認するのが良いと書いてあったので、
大変でしたが自分で読み解いてみました。
読み解くと結構時間かかったので、
今後、同じ想いで苦労する人を救いたい一心で結果を図示してみました。
裏側のcloudformationを図示
全部読み解くと、下記のようになっていました。
control towerの全体図です。
裏側のcloudformation詳細
ここからは各stackの中身を記載していきます。
読み解く時にはメモが参考になると思います。
もし間違いを見つけた場合は、ご連絡いただけますと嬉しいです。
AWSControlTowerBP-BASELINE-CLOUDTRAIL
概要
trailを有効化し結果をS3とlogsに出力する
S3はアーカイブアカウント宛で、マルチリージョンを記録します
logs連携は有効化され、retentionは14日
configはsnsを設定、セキュリティアカウントの「aws-controltower-AllConfigNotification」に通知 します
デプロイ対象
下記のcontroltowerを有効化した1つのリージョン
core ou
custome ou
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure AWS CloudTrail Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' EnableLogFileValidation: Type: String Default: 'true' Description: Indicates whether CloudTrail validates the integrity of log files. AllowedValues: - 'true' - 'false' IncludeGlobalEvents: Type: String Default: 'true' Description: Indicates whether the trail is publishing events from global services, such as IAM, to the log files. AllowedValues: - 'true' - 'false' MultiRegion: Type: String Default: 'true' Description: Indicates whether the CloudTrail trail is created in the region in which you create the stack (false) or in all regions (true). AllowedValues: - 'true' - 'false' AllConfigTopicName: Type: String Default: '' Description: All Configuration Notification SNS Topic in Security Account that AWS Config delivers notifications to. SecurityAccountId: Type: 'String' Description: AWS Account Id of the Security account. AuditBucketName: Type: String Default: '' Description: Audit Bucket name from the Log Archive Account PublishToCloudWatchLogs: Type: String Default: 'true' Description: Indicates whether notifications are published to CloudWatch Logs. AllowedValues: - 'true' - 'false' LogsRetentionInDays: Description: 'Specifies the number of days you want to retain CloudTrail log events in the CloudWatch Logs.' Type: Number Default: 14 AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] AWSLogsS3KeyPrefix: Type: 'String' Description: 'Organization ID to use as the S3 Key prefix for storing the audit logs' Conditions: IsMultiRegion: !Equals - !Ref MultiRegion - 'true' IsPublishToCloudWatchLogs: !Equals - !Ref PublishToCloudWatchLogs - 'true' Resources: Trail: Type: AWS::CloudTrail::Trail Properties: TrailName: !Sub ${ManagedResourcePrefix}-BaselineCloudTrail S3BucketName: !Ref AuditBucketName S3KeyPrefix: !Ref AWSLogsS3KeyPrefix SnsTopicName: !Sub arn:aws:sns:${AWS::Region}:${SecurityAccountId}:${AllConfigTopicName} IsLogging: True EnableLogFileValidation: !Ref EnableLogFileValidation IncludeGlobalServiceEvents: !If - IsMultiRegion - True - !Ref IncludeGlobalEvents IsMultiRegionTrail: !Ref MultiRegion CloudWatchLogsLogGroupArn: !If - IsPublishToCloudWatchLogs - !GetAtt TrailLogGroup.Arn - !Ref AWS::NoValue CloudWatchLogsRoleArn: !If - IsPublishToCloudWatchLogs - !GetAtt TrailLogGroupRole.Arn - !Ref AWS::NoValue TrailLogGroup: Type: 'AWS::Logs::LogGroup' Condition: IsPublishToCloudWatchLogs Properties: LogGroupName: !Sub ${ManagedResourcePrefix}/CloudTrailLogs RetentionInDays: !Ref LogsRetentionInDays TrailLogGroupRole: Type: 'AWS::IAM::Role' Condition: IsPublishToCloudWatchLogs Properties: RoleName: !Sub ${ManagedResourcePrefix}-CloudWatchLogsRole AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Sid: CloudTrailAssumeRole Effect: Allow Principal: Service: 'cloudtrail.amazonaws.com' Action: 'sts:AssumeRole' Policies: - PolicyName: 'cloudtrail-policy' PolicyDocument: Version: '2012-10-17' Statement: - Sid: AWSCloudTrailCreateLogStream Effect: Allow Action: 'logs:CreateLogStream' Resource: !GetAtt 'TrailLogGroup.Arn' - Sid: AWSCloudTrailPutLogEvents Effect: Allow Action: 'logs:PutLogEvents' Resource: !GetAtt 'TrailLogGroup.Arn' Outputs: BaselineCloudTrail: Description: Baseline CloudTrail Value: !GetAtt 'Trail.Arn' CloudWatchLogsGroupArn: Description: CloudWatch Log Group ARN for Baseline CloudTrail Value: !GetAtt 'TrailLogGroup.Arn' CloudWatchLogsGroupName: Description: CloudWatch Log Group Name for Baseline CloudTrail Value: !Ref TrailLogGroup
AWSControlTowerBP-BASELINE-CLOUDWATCH
概要
LambdaとSNS。
configのルールに準拠していない場合は、子アカウントのLambdaを経由して
AuditアカウントのSNSに通知する
デフォルトではSNSの名前は下記になっている
aws-controltower-AggregateSecurityNotifications
デプロイ対象
下記のcontroltowerがサポートされている全リージョン
core ou
custome ou
cloudformation template
--- AWSTemplateFormatVersion: '2010-09-09' Description: Configure Cloudwatch Rule, local SNS Topic, forwarding notifications from local SNS Topic to Security Topic Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' SecurityTopicName: Type: String Description: Security Notification SNS Topic Name. SecurityAccountId: Type: 'String' Description: AWS Account Id of the Security account. LogsRetentionInDays: Description: 'Specifies the number of days you want to retain notification forwarding log events in the Lambda log group.' Type: Number Default: 14 AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] EnableConfigRuleComplianceChangeAlarm: Type: String Description: "Enable notifications for AWS Config rule compliance status changes?" Default: true AllowedValues: - true - false Mappings: TopicNameSuffix: LocalTopicName: Suffix: 'SecurityNotifications' Conditions: EnableConfigRuleChangeNotification: !Equals - !Ref EnableConfigRuleComplianceChangeAlarm - 'true' Resources: ForwardSnsNotification: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub ${ManagedResourcePrefix}-NotificationForwarder Description: SNS message forwarding function for aggregating account notifications. Code: ZipFile: !Sub | from __future__ import print_function import boto3 import json import os def lambda_handler(event, context): #print("Received event: " + json.dumps(event, indent=2)) sns = boto3.client('sns') subject=event['Records'][0]['Sns']['Subject'] if subject is None: subject = 'None' message = event['Records'][0]['Sns']['Message'] try: msg = json.loads(message) message = json.dumps(msg, indent=4) if 'detail-type' in msg: subject = msg['detail-type'] except: print('Not json') response = sns.publish( TopicArn=os.environ.get('sns_arn'), Subject=subject, Message=message ) print(response) return response Handler: 'index.lambda_handler' MemorySize: 128 Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${ManagedResourcePrefix}-ForwardSnsNotificationRole Runtime: 'python3.6' Timeout: 60 Environment: Variables: sns_arn: !Sub arn:aws:sns:${AWS::Region}:${SecurityAccountId}:${SecurityTopicName} ForwardSnsNotificationGroup: Type: 'AWS::Logs::LogGroup' Properties: LogGroupName: !Sub '/aws/lambda/${ForwardSnsNotification}' RetentionInDays: !Ref LogsRetentionInDays LocalSecurityTopic: Type: AWS::SNS::Topic Properties: DisplayName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, LocalTopicName, Suffix] ]] TopicName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, LocalTopicName, Suffix] ]] SNSNotificationPolicy: Type: AWS::SNS::TopicPolicy Metadata: cfn_nag: rules_to_suppress: - id: F18 reason: "Condition restricts permissions to current account." Properties: Topics: - !Ref LocalSecurityTopic PolicyDocument: Statement: - Sid: __default_statement_ID Effect: Allow Principal: AWS: "*" Action: - SNS:GetTopicAttributes - SNS:SetTopicAttributes - SNS:AddPermission - SNS:RemovePermission - SNS:DeleteTopic - SNS:Subscribe - SNS:ListSubscriptionsByTopic - SNS:Publish - SNS:Receive Resource: !Ref LocalSecurityTopic Condition: StringEquals: AWS:SourceOwner: !Sub ${AWS::AccountId} - Sid: TrustCWEToPublishEventsToMyTopic Effect: Allow Principal: Service: events.amazonaws.com Action: sns:Publish Resource: !Ref LocalSecurityTopic SNSNotificationSubscription: Type: "AWS::SNS::Subscription" Properties: Endpoint: !GetAtt ForwardSnsNotification.Arn Protocol: lambda TopicArn: !Ref LocalSecurityTopic SNSInvokeLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction Principal: sns.amazonaws.com SourceArn: !Ref LocalSecurityTopic FunctionName: !GetAtt ForwardSnsNotification.Arn # Enable notifications for AWS Config Rule compliance changes CWEventRuleComplianceChangeEvent: Type: AWS::Events::Rule Condition: EnableConfigRuleChangeNotification Properties: Name: !Sub ${ManagedResourcePrefix}-ConfigComplianceChangeEventRule Description: 'CloudWatch Event Rule to send notification on Config Rule compliance changes.' EventPattern: { "source": [ "aws.config" ], "detail-type": [ "Config Rules Compliance Change" ] } State: ENABLED Targets: - Id: !Sub 'Compliance-Change-Topic' Arn: !Ref LocalSecurityTopic Outputs: LocalSecurityTopic: Description: Local Security Notification SNS Topic ARN Value: !Ref LocalSecurityTopic LocalSecurityTopicName: Description: Local Security Notification SNS Topic Name Value: !GetAtt LocalSecurityTopic.TopicName
AWSControlTowerBP-BASELINE-CONFIG
概要
configを有効化し、security(Audit)のアカウントにアグリゲーションする configの通知はsecurity(Audit)のアカウントの下記に通知する aws-controltower-AllConfigNotifications
デプロイ対象
下記のcontroltowerがサポートされている全リージョン
core ou
custome ou
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure AWS Config Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' AllSupported: Type: String Default: 'true' Description: Indicates whether to record all supported resource types. AllowedValues: - 'true' - 'false' IncludeGlobalResourceTypes: Type: String Default: 'true' Description: Indicates whether AWS Config records all supported global resource types. AllowedValues: - 'true' - 'false' ResourceTypes: Type: CommaDelimitedList Description: A list of valid AWS resource types to include in this recording group. Eg. AWS::CloudTrail::Trail Frequency: Type: String Default: 1hour Description: The frequency with which AWS Config delivers configuration snapshots. AllowedValues: - 1hour - 3hours - 6hours - 12hours - 24hours AllConfigTopicName: Type: String Default: '' Description: All Configuration Notification SNS Topic in Security Account that AWS Config delivers notifications to. SecurityAccountId: Type: 'String' Description: AWS Account Id of the Security account. AuditBucketName: Type: String Default: '' Description: Audit Bucket name from the Log Archive Account AWSLogsS3KeyPrefix: Type: 'String' Description: Organization ID to use as the S3 Key prefix for storing the audit logs HomeRegionName: Type: 'String' Description: The name of the home region for the customer IsHomeRegionInitialControlTowerRegion: Type: 'String' AllowedValues: - 'true' - 'false' Description: Indicates whether the Home Region of the customer is one of the initial regions in which AWS Control Tower launched. Conditions: IsAllSupported: !Equals - !Ref AllSupported - 'true' CreateHomeRegionConfigAggregatorAuthorization: !Equals - !Ref IsHomeRegionInitialControlTowerRegion - 'false' CreateRegionalConfigAggregatorAuthorization: !Equals - !Ref IsHomeRegionInitialControlTowerRegion - 'true' Mappings: Settings: FrequencyMap: 1hour : One_Hour 3hours : Three_Hours 6hours : Six_Hours 12hours : Twelve_Hours 24hours : TwentyFour_Hours Resources: ConfigRecorder: Type: AWS::Config::ConfigurationRecorder Properties: Name: !Sub ${ManagedResourcePrefix}-BaselineConfigRecorder RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/${ManagedResourcePrefix}-ConfigRecorderRole RecordingGroup: AllSupported: !Ref AllSupported IncludeGlobalResourceTypes: !Ref IncludeGlobalResourceTypes ResourceTypes: !If - IsAllSupported - !Ref AWS::NoValue - !Ref ResourceTypes ConfigDeliveryChannel: Type: AWS::Config::DeliveryChannel Properties: Name: !Sub ${ManagedResourcePrefix}-BaselineConfigDeliveryChannel ConfigSnapshotDeliveryProperties: DeliveryFrequency: !FindInMap - Settings - FrequencyMap - !Ref Frequency S3BucketName: !Ref AuditBucketName S3KeyPrefix: !Ref AWSLogsS3KeyPrefix SnsTopicARN: !Sub arn:aws:sns:${AWS::Region}:${SecurityAccountId}:${AllConfigTopicName} AuthorizerPdx: Condition: CreateRegionalConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: us-west-2 AuthorizerIad: Condition: CreateRegionalConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: us-east-1 AuthorizerCmh: Condition: CreateRegionalConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: us-east-2 AuthorizerDub: Condition: CreateRegionalConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: eu-west-1 AuthorizerSyd: Condition: CreateRegionalConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: ap-southeast-2 HomeRegionAuthorizer: Condition: CreateHomeRegionConfigAggregatorAuthorization Type: "AWS::Config::AggregationAuthorization" Properties: AuthorizedAccountId: !Ref SecurityAccountId AuthorizedAwsRegion: !Ref HomeRegionName Outputs: BaselineConfigRecorder: Description: Baseline Config Recorder Value: !Ref ConfigRecorder BaselineConfigDeliveryChannel: Description: Baseline Config Delivery Channel Value: !Ref ConfigDeliveryChannel
AWSControlTowerBP-BASELINE-ROLES
概要
Auditのアカウントからスイッチロールが可能なよう
readonlyとadminの2種類のroleを作成する
デプロイ対象
下記のcontroltowerが有効化された単一リージョン
core ou
custome ou
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure the Cross-Account IAM Security Roles for the member accounts. Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' SecurityAccountAdminRoleArn: Type: String Description: Admin role ARN from the security account. SecurityAccountReadOnlyRoleArn: Type: String Description: Admin role ARN from the security account. EnableAdminRole: Type: String Default: 'true' Description: Create an administrative cross-account role from Security Account to this account. AllowedValues: - 'true' - 'false' EnableReadOnlyRole: Type: String Default: 'true' Description: Create a read-only cross-account role from Security Account to this account. AllowedValues: - 'true' - 'false' Conditions: CreateAdminRole: !Equals - !Ref EnableAdminRole - 'true' CreateReadOnlyRole: !Equals - !Ref EnableReadOnlyRole - 'true' Resources: AdminExecutionRole: Type: AWS::IAM::Role Condition: CreateAdminRole Properties: RoleName: !Sub ${ManagedResourcePrefix}-AdministratorExecutionRole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: - !Ref SecurityAccountAdminRoleArn Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AdministratorAccess ReadOnlyExecutionRole: Type: AWS::IAM::Role Condition: CreateReadOnlyRole Properties: RoleName: !Sub ${ManagedResourcePrefix}-ReadOnlyExecutionRole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: - !Ref SecurityAccountReadOnlyRoleArn Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/ReadOnlyAccess
AWSControlTowerBP-BASELINE-SERVICE-ROLES
概要
AWSControlTowerBP-BASELINE-CLOUDWATCH
の実行に必要なlambdaとconfig用のロールを作成する
デプロイ対象
下記のcontroltowerが有効化された単一リージョン core ou custome ou
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure AWS Config and SNS Notification Forward IAM Roles Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' SecurityTopicName: Type: String Description: Security Notification SNS Topic Name. SecurityAccountId: Type: 'String' Description: AWS Account Id of the Security account. Resources: ConfigRecorderRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ManagedResourcePrefix}-ConfigRecorderRole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - config.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSConfigRole - arn:aws:iam::aws:policy/ReadOnlyAccess ForwardSnsNotificationLambdaRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub ${ManagedResourcePrefix}-ForwardSnsNotificationRole AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: 'lambda.amazonaws.com' Action: - 'sts:AssumeRole' Path: '/' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: sns PolicyDocument: Statement: - Effect: Allow Action: - 'sns:publish' Resource: !Sub arn:aws:sns:*:${SecurityAccountId}:${SecurityTopicName} Outputs: BaselineConfigRole: Description: Baseline Config Role Value: !GetAtt 'ConfigRecorderRole.Arn'
AWSControlTowerBP-SECURITY-TOPICS
概要
SNSのtopicを2つ作成する
AggregateSecurityNotifications
AllConfigNotifications
各アカウントで何かあったときの受け口となるSNS Topic
対象
下記のcontroltowerがサポートされている全リージョン audit
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure the SNS Topics for Security Account Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' AllConfigurationEmail: Type: 'String' Description: Email for receiving all AWS configuration events SecurityNotificationEmail: Type: 'String' Description: Email for the security administrator(s) OrgID: Type: 'String' Description: AWS Organizations ID to allow notifications from member accounts SubscribeToAllConfigurationTopic: Type: String Default: false Description: Indicates whether AllConfigurationEmail will be subscribed to the AllConfigurationTopicName topic. AllowedValues: - true - false Conditions: Subscribe: !Equals - !Ref SubscribeToAllConfigurationTopic - 'true' Mappings: TopicNameSuffix: AllConfigurationTopicName: Suffix: 'AllConfigNotifications' NotifyTopicName: Suffix: 'AggregateSecurityNotifications' Resources: SNSAllConfigurationTopic: Type: AWS::SNS::Topic Properties: DisplayName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, AllConfigurationTopicName, Suffix] ]] TopicName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, AllConfigurationTopicName, Suffix] ]] SNSAllConfigurationTopicPolicy: Type: AWS::SNS::TopicPolicy Properties: Topics: - !Ref SNSAllConfigurationTopic PolicyDocument: Statement: - Sid: AWSSNSPolicy Action: - sns:Publish Effect: Allow Resource: !Ref SNSAllConfigurationTopic Principal: Service: - cloudtrail.amazonaws.com - config.amazonaws.com SNSAllConfigurationEmailNotification: Condition: Subscribe Type: AWS::SNS::Subscription Properties: Endpoint: !Ref AllConfigurationEmail Protocol: email TopicArn: !Ref SNSAllConfigurationTopic SNSNotification: Type: AWS::SNS::Topic Properties: DisplayName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, NotifyTopicName, Suffix] ]] TopicName: !Join [ "-", [ !Ref ManagedResourcePrefix, !FindInMap [TopicNameSuffix, NotifyTopicName, Suffix] ]] Subscription: - Protocol: email Endpoint: !Ref SecurityNotificationEmail SNSNotificationPolicy: Type: AWS::SNS::TopicPolicy Metadata: cfn_nag: rules_to_suppress: - id: F18 reason: "Conditions restrict permissions to Organization account and publishing only to member accounts." Properties: Topics: - !Ref SNSNotification PolicyDocument: Statement: - Sid: __default_statement_ID Effect: Allow Principal: AWS: "*" Action: - SNS:GetTopicAttributes - SNS:SetTopicAttributes - SNS:AddPermission - SNS:RemovePermission - SNS:DeleteTopic - SNS:Subscribe - SNS:ListSubscriptionsByTopic - SNS:Publish - SNS:Receive Resource: !Ref SNSNotification Condition: StringEquals: AWS:SourceOwner: !Sub ${AWS::AccountId} - Sid: AWSSNSPolicy Effect: Allow Principal: AWS: "*" Action: sns:Publish Resource: !Ref SNSNotification Condition: StringEquals: aws:PrincipalOrgID: !Ref OrgID Outputs: SecurityTopicARN: Description: Security Notification SNS Topic ARN Value: !Ref SNSNotification SecurityTopicName: Description: Security Notification SNS Topic Name Value: !GetAtt SNSNotification.TopicName AllConfigTopicARN: Description: All Configuration Notification SNS Topic ARN Value: !Ref SNSAllConfigurationTopic AllConfigTopicName: Description: All Configuration Notification SNS Topic Name Value: !GetAtt SNSAllConfigurationTopic.TopicName
AWSControlTowerGuardrailAWS-GR-AUDIT-BUCKET-PUBLIC-READ-PROHIBITED
概要
config ruleを作成する
ルール:S3_BUCKET_PUBLIC_READ_PROHIBITED
デプロイ対象
下記のcontroltowerがサポートされている全リージョン
Log archive
audit
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure AWS Config rules to check that your S3 buckets do not allow public access Parameters: ConfigRuleName: Type: 'String' Description: 'Name for the Config rule' Resources: CheckForS3PublicRead: Type: AWS::Config::ConfigRule Properties: ConfigRuleName: !Sub ${ConfigRuleName} Description: Checks that your S3 buckets do not allow public read access. If an S3 bucket policy or bucket ACL allows public read access, the bucket is noncompliant. Source: Owner: AWS SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED Scope: ComplianceResourceTypes: - AWS::S3::Bucket
AWSControlTowerGuardrailAWS-GR-AUDIT-BUCKET-PUBLIC-WRITE-PROHIBITED
概要
config ruleを作成する
ルール:S3_BUCKET_PUBLIC_WRITE_PROHIBITED
デプロイ対象
下記のcontroltowerがサポートされている全リージョン
Log archive
audit
AWSTemplateFormatVersion: 2010-09-09 Description: Configure AWS Config rules to check that your S3 buckets do not allow public access Parameters: ConfigRuleName: Type: 'String' Description: 'Name for the Config rule' Resources: CheckForS3PublicWrite: Type: AWS::Config::ConfigRule Properties: ConfigRuleName: !Sub ${ConfigRuleName} Description: Checks that your S3 buckets do not allow public write access. If an S3 bucket policy or bucket ACL allows public write access, the bucket is noncompliant. Source: Owner: AWS SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED Scope: ComplianceResourceTypes: - AWS::S3::Bucket
AWSControlTowerLoggingResources
概要
バケットを2つ作成する
1つはaudit。ここに他アカウントからのconfigやtrail結果が書き込まれる
2つ目は上記のs3へのアクセスログを記録するためのバケット
デプロイ対象
下記のcontroltowerが有効化された単一リージョン
Log archive
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure an Audit S3 bucket for the Log Archive account. Parameters: SSEAlgorithm: Type: 'String' Default: 'AES256' Description: S3 bucket SSE Algorithm. AllowedValues: - 'AES256' - 'aws:kms' KMSMasterKeyID: Type: 'String' Description: 'KMS key ID required if SSE algorithm is aws:kms.' ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' RetentionDays: Type: String Description: 'No of Days to retain the logs, after which it will be permanently deleted' TransitionToGlacier: Type: String Description: 'Do you wish to transition the logs to Glacier before permanently deleting?' Default: 'No' AllowedValues: - 'Yes' - 'No' TransitionDays: Type: String Description: 'No of Days to transition the data from S3 to Glacier' AWSLogsS3KeyPrefix: Type: 'String' Description: 'Organization ID to use as the S3 Key prefix for storing the audit logs' Conditions: UseKMS: !Equals - !Ref SSEAlgorithm - 'aws:kms' MoveToGlacier: !Equals - !Ref TransitionToGlacier - 'Yes' Resources: # Create S3 Server Access Logging bucket S3LoggingBucket: DeletionPolicy: Retain Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ManagedResourcePrefix}-s3-access-logs-${AWS::AccountId}-${AWS::Region} AccessControl: LogDeliveryWrite VersioningConfiguration: Status: Enabled BucketEncryption: ServerSideEncryptionConfiguration: - !If - UseKMS - ServerSideEncryptionByDefault: SSEAlgorithm: !Ref SSEAlgorithm KMSMasterKeyID: !Ref KMSMasterKeyID - ServerSideEncryptionByDefault: SSEAlgorithm: !Ref SSEAlgorithm # Create S3 Audit bucket S3AuditBucket: DeletionPolicy: Retain Type: AWS::S3::Bucket Properties: BucketName: !Sub ${ManagedResourcePrefix}-logs-${AWS::AccountId}-${AWS::Region} VersioningConfiguration: Status: Enabled LoggingConfiguration: DestinationBucketName: !Ref S3LoggingBucket BucketEncryption: ServerSideEncryptionConfiguration: - !If - UseKMS - ServerSideEncryptionByDefault: SSEAlgorithm: !Ref SSEAlgorithm KMSMasterKeyID: !Ref KMSMasterKeyID - ServerSideEncryptionByDefault: SSEAlgorithm: !Ref SSEAlgorithm LifecycleConfiguration: Rules: - !If - MoveToGlacier - Id: RetentionRule Status: Enabled ExpirationInDays: !Ref RetentionDays NoncurrentVersionExpirationInDays: !Ref RetentionDays Transitions: - TransitionInDays: !Ref TransitionDays StorageClass: Glacier NoncurrentVersionTransitions: - TransitionInDays: !Ref TransitionDays StorageClass: Glacier - Id: RetentionRule Status: Enabled ExpirationInDays: !Ref RetentionDays NoncurrentVersionExpirationInDays: !Ref RetentionDays # Create Bucket Policy for S3 Audit bucket S3AuditBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref S3AuditBucket PolicyDocument: Version: 2012-10-17 Statement: - Sid: AWSBucketPermissionsCheck Effect: Allow Principal: Service: - cloudtrail.amazonaws.com - config.amazonaws.com Action: s3:GetBucketAcl Resource: - !Sub "arn:aws:s3:::${S3AuditBucket}" - Sid: AWSBucketDelivery Effect: Allow Principal: Service: - cloudtrail.amazonaws.com - config.amazonaws.com Action: s3:PutObject Resource: - Fn::Join: - "" - - "arn:aws:s3:::" - !Ref "S3AuditBucket" - !Sub "/${AWSLogsS3KeyPrefix}/AWSLogs/*/*" Outputs: BucketName: Description: Audit S3 bucket name Value: !Ref S3AuditBucket LoggingBucketName: Description: S3 Access Logging Bucket name Value: !Ref S3LoggingBucket AuditLogsS3KeyPrefix: Description: S3 Key prefix for storing the audit logs Value: !Ref AWSLogsS3KeyPrefix
AWSControlTowerSecurityResources
概要
Lambda実行用のロール(adminとreadonlyの2つ)
対象
下記のcontroltowerが有効化された単一リージョン
audit
cloudformation template
AWSTemplateFormatVersion: 2010-09-09 Description: Configure the Cross-Account IAM Audit Roles for Audit Account Parameters: ManagedResourcePrefix: Type: 'String' Description: 'Prefix for the managed resources' AuditAccountId: Type: 'String' Description: 'Audit account Id' LoggingAccountId: Type: 'String' Description: 'Logging account Id' Resources: AdministrationRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ManagedResourcePrefix}-AuditAdministratorRole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSLambdaExecute Policies: - PolicyName: !Sub AssumeRole-${ManagedResourcePrefix}-AuditAdministratorRole PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Resource: - !Sub "arn:aws:iam::*:role/${ManagedResourcePrefix}-AdministratorExecutionRole" ReadOnlyRole: Type: AWS::IAM::Role Properties: RoleName: !Sub ${ManagedResourcePrefix}-AuditReadOnlyRole AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/AWSLambdaExecute Policies: - PolicyName: !Sub AssumeRole-${ManagedResourcePrefix}-AuditReadOnlyRole PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - sts:AssumeRole Resource: - !Sub "arn:aws:iam::*:role/${ManagedResourcePrefix}-ReadOnlyExecutionRole" # AWSConfig Aggregator for Guardrail compliance GuardrailsComplianceAggregator: Type: AWS::Config::ConfigurationAggregator Properties: AccountAggregationSources: - AccountIds: - !Ref AuditAccountId - !Ref LoggingAccountId AllAwsRegions: true ConfigurationAggregatorName: !Sub ${ManagedResourcePrefix}-GuardrailsComplianceAggregator Outputs: CrossAccountAdminRole: Description: Audit Administrator Role Value: !GetAtt 'AdministrationRole.Arn' CrossAccountReadOnlyRole: Description: Audit ReadOnly Role Value: !GetAtt 'ReadOnlyRole.Arn'
最後に
役に立った人がいれば褒めて欲しい。。。。
Organization管理は、自社の管理しか深く関わらず、
サンプル数が少ないので
他の詳しい人の考え方も聞きたいと思う事がよくあります。
何かあればコメント頂けると嬉しいです。
AWS fsx を作った後にやること
AWS fsxを作成した後、AWSコンソールから以外ですべき設定作業があります。
それがこちら。 docs.aws.amazon.com
概要をざっとまとめるとこちらです。
Best Practices
項目 | 機能概要 | 関連リンク |
---|---|---|
Data Deduplication | データの重複を極力削減してくれる機能 | link |
quota | データ要領の利用制限をADグループ等に対し設定できる機能 | link |
shadow copy | メリット:ファイル/フォルダ単位でのリストアが簡単に可能 デメリット:FSXの一部の要領をshadow copy用に利用する |
link link2 |
Encryption in Transit | クライアントから接続の際、暗号化通信を設定する | link |
上記はAWSが言うところのベストプラクティスです。 ただ、上記以外にもやっておいた方が良さげなことがあります。
おすすめ
項目 | 機能概要 | 関連リンク |
---|---|---|
DNS Alias | fsxに別のfqdnを付与できます リストアとかした時に便利です Deployment typeがSingle-AZ 1の時のみ利用可能なので注意です |
link |
Shared Folders tool | 接続ユーザの一覧や、ファイルがロックされてしまった場合に解除できる。設定ではないが一回触っておいた方が良い | link |
cloudwatch Alarm | 残りの容量が少ない場合通知設定をする | link |
設定してみる
では、上記を設定してみます。
まず環境変数を設定します。
全ての作業の前で、下記を実行してください。
環境変数設定
下記を「Windows Remote PowerShell Endpoint」の部分に置き換えて実行します。
#poweshell endpointを設定する $FSxWindowsRemotePowerShellEndpoint="amznfsxxxxxxxxxx.fsx-test.local"
Data Deduplication(データ重複削減)
機能概要
この機能が有効化されていると、
定期的にバックグラウンドで、データ重複を検知し、
ディスクの要領を削減してくれます。
設定方法
# depulicationを有効化 Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Enable-FsxDedup }
有効化するとデフォルトで良い感じにスケジュール実行してくれるそうです。
スケジュールを明確に指定する方法もあるようです。
docs.aws.amazon.com
Quota
機能概要
fsx本来要領に対しquota(制限)を設定できる機能です。
具体的には、ADの特定グループと、制限値を設定できるため、
ファイルサーバ的に利用している場合に、
特定のグループの人はxxGBまで、と要領制限を付けたい場合に利用すると良いと思います。
設定方法
## 記録のみしたい場合(Trackモード) $QuotaLimit = 100000000 $QuotaWarningLimit = 100000 Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Enable-FSxUserQuotas -Track -DefaultLimit $Using:QuotaLimit -DefaultWarningLimit $Using:QuotaWarningLimit }
## 要領を超えた場合に、強制的に書き込みを禁止したい場合(Enforceモード) $QuotaLimit = 100000000 $QuotaWarningLimit = 100000 Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Enable-FSxUserQuotas -Enforce -DefaultLimit $Using:QuotaLimit -DefaultWarningLimit $Using:QuotaWarningLimit }
## 現在のモードを確認する(enforceかtrackか) Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Get-FSxUserQuotaSettings }
## 特定のADのグループに制限を紐付けたい場合(例.グループ名:fsxservice) Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Set-FSxUserQuotas -Domain "fsx-test.local" -Name "fsxservice" -Limit 10 -WarningLimit 5 }
shadow copy
機能概要
fsx内のデータを特定時点に復元したいとき、
バックアップからリストアが必要となります。
ただ、間違えてファイル上書きしてしまって、
特定のファイルだけ戻したいみたいなケースは良くあると思います。
そんな時、shadow copyを有効化しておくと、
特定のファイルだけ復元が可能です。
復元時の操作イメージは下記が分かりやすいと思います。
docs.aws.amazon.com
設定方法
#shadow copyを有効化 Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Set-FsxShadowStorage -Default } #shadow copyのスケジュールを作成 $trigger1 = new-scheduledTaskTrigger -weekly -DaysOfWeek Monday,Tuesday,Wednesday,Thursday,Friday -at 06:00 $trigger2 = new-scheduledTaskTrigger -weekly -DaysOfWeek Monday,Tuesday,Wednesday,Thursday,Friday -at 18:00 invoke-command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -scriptblock { set-fsxshadowcopyschedule -scheduledtasktriggers $Using:trigger1,$Using:trigger2 -Confirm:$false } # スケジュール確認 Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Get-FsxShadowCopySchedule }
Encryption in Transit
クライアントから接続の際、
通信を暗号化通信を強制します。
設定方法
#Enforcing Encryption in Transit Invoke-Command -ComputerName $FSxWindowsRemotePowerShellEndpoint -ConfigurationName FSxRemoteAdmin -ScriptBlock { Set-FsxSmbServerConfiguration -EncryptData $True -RejectUnencryptedAccess $True -Confirm:$False}
DNS Alias
機能概要
通常、fsxが作成されるとID的に1つのFQDN(amznxxxxx.<ドメイン名>)が割り当てられます。
ただ、FQDNをリストアした場合や、 移行等の場合では、
固有のFQDNだと、設定変更が発生して面倒かと思います。
DNS Aliasを利用すると別のDNS名をつけることが可能です。
設定方法
まず、AWSコンソールで「DNS Alias」から指定したいエイリアス名を入力します。
その後、ドメイン参加のサーバからpowershell側で設定を追加します。
ドキュメントのサンプルは何回も環境変数をsetして
面倒だったため、まとめています。
$ALIAS = "fsx.fsx-test.local" $FileSystemDnsName = "amznfsxjlrqzujy.fsx-test.local" Install-WindowsFeature RSAT-AD-PowerShell ## Find SPNs for original file system's AD computer object SetSPN /Q ("HOST/" + $ALIAS) SetSPN /Q ("HOST/" + $ALIAS.Split(".")[0]) ## Delete SPNs for original file system's AD computer object $Alias = $ALIAS $FileSystemHost = (Resolve-DnsName ${FileSystemDnsName} | Where Type -eq 'A')[0].Name.Split(".")[0] $FSxAdComputer = (Get-AdComputer -Identity ${FileSystemHost}) SetSPN /D ("HOST/" + ${Alias}) ${FSxAdComputer}.Name SetSPN /D ("HOST/" + ${Alias}.Split(".")[0]) ${FSxAdComputer}.Name ## Set SPNs for FSx file system AD computer object $FSxDnsName = $FileSystemDnsName $FileSystemHost = (Resolve-DnsName $FSxDnsName | Where Type -eq 'A')[0].Name.Split(".")[0] $FSxAdComputer = (Get-AdComputer -Identity $FileSystemHost) Set-AdComputer -Identity $FSxAdComputer -Add @{"msDS-AdditionalDnsHostname"="$Alias"} SetSpn /S ("HOST/" + $Alias.Split('.')[0]) $FSxAdComputer.Name SetSpn /S ("HOST/" + $Alias) $FSxAdComputer.Name ## Verify SPNs on FSx file system AD computer object $FileSystemHost = (Resolve-DnsName ${FSxDnsName} | Where Type -eq 'A')[0].Name.Split(".")[0] $FSxAdComputer = (Get-AdComputer -Identity ${FileSystemHost}) SetSpn /L ${FSxAdComputer}.Name
続いてDNS設定です。
こちらはADが動いているサーバで実行しました。
ドキュメント内のコマンドでうまくいかない点が
あったため一部修正しています。
Alias,FSxDnsNameを上記の部分に置き換えて実行します。
$Alias = "fsx.fsx-test.local" $FSxDnsName = "amznfsxjlrqzujy.fsx-test.local" Install-WindowsFeature RSAT-DNS-Server $AliasHost=$Alias.Split('.')[0] $ZoneName=((Get-WmiObject Win32_ComputerSystem).Domain) $DnsServerComputerName = (Resolve-DnsName $ZoneName -Type NS | Where Type -eq 'A' | Select -ExpandProperty Name) Add-DnsServerResourceRecordCName -Name $AliasHost -ComputerName $DnsServerComputerName -HostNameAlias $FSxDnsName -ZoneName $ZoneName
GPOを設定する
意味的にはNTLMを利用せずKerberos認証を強制するよう
グループポリシーを設することのようです。
強制したくない場合もあると思いますので、
一部の例外も併せて設定できます。
gpmc.mscを開きます
対象のOUでグループポリシーを作成しEditします。
Localポリシー内の下記を選択します
Restrict NTLM: Outgoing NTLM traffic to remote servers
続いてLocalポリシー内の下記を選択します
Restrict NTLM: Add remote server exceptions for NTLM authentication
例外を指定したい場合はここで入力します。
上記が完了したら、エイリアス名で正しく名前解決ができることを確認します。
PS C:\Users\Administrator> nslookup fsx.fsx-test.local Server: localhost Address: ::1 Name: amznfsxjlrqzujy.fsx-test.local Address: 172.30.5.102 Aliases: fsx.fsx-test.local
その後、fsxに接続し、成功すれば完了です
net use z: \\fsx.fsx-test.local\share
Shared Folders tool
機能概要
下記のようなケースで管理者が使うツールです。
こちらは設定しておくものでなく、
管理者が利用するケースがあると思いますので、
構築したタイミングで動作を試してみると良いと思います。
- FSXへの接続セッションを強制で切る
- ファイルが競合してうまく開かない等あったら解決できる
利用方法
fsmgmt.msc
fsxのdns名を入力
その後、セッションを終了させる、
ファイル競合を解決する操作は下記が分かりやすいです。
docs.aws.amazon.com
cloudwatch Alarm
下記参考にFreeStorageCapacity(空き容量)の通知ぐらいは
しておいた方が良いかと思いました。
docs.aws.amazon.com
下記をまとめて作成するcloudformaitonを下記ました。
自己所有のADを参照するFsx用の記述のため
MicrosoftADをご利用の場合は、その部分を書き換えが必要です。
あと、各種パラメータは読み替えてください。
- fsx
- security-group
- SNS
- cloudwatch
AWSTemplateFormatVersion: "2010-09-09" Description: A templete for fsx for windows Parameters: EnvPrefix: Type: String Default: "test" # KmsKeyId: # Type: String StorageCapacity: Type: Number Default : 32 VPCId: Type: AWS::EC2::VPC::Id Default: vpc-xxxxxxxxx SubnetIds: Type: List<AWS::EC2::Subnet::Id> Default: subnet-xxxxxxxxxx # ActiveDirectoryId: # Type: String # Default: d-96671b8248 DailyAutomaticBackupStartTime: Type: String Default: "16:00" DeploymentType: Type: String Default: SINGLE_AZ_2 # Default: MULTI_AZ_1 ThroughputCapacity: Type: Number Default : 8 WeeklyMaintenanceStartTime: Type: String Default: "6:17:00" OnpreDNS: Type: CommaDelimitedList Default: xxx.xxx.xxx.xxx OnpreDomainName: Type: String Default: fsx-test.local FileSystemAdministratorsGroup: Type: String Default: FSXAdmins UserName: Type: String Default: fsxservice Password: Type: String Default: xxxxxxxxxxxxxxxxxxxxxxxxxx NoEcho: True OrganizationalUnitDistinguishedName: Type: String Default: "OU=FileSystems,DC=fsx-test,DC=local" FSXAllowedRange: Type: String Default: 172.30.0.0/16 ThresholdFreeStorageCapacity: Type: Number Default: 3221225472 endpointEmail: Type: String Default: 'xxxxxxxxxxxxxx@xxxxxx.com' Resources : fsx: Type: AWS::FSx::FileSystem Properties: # KmsKeyId: kms FileSystemType: WINDOWS SecurityGroupIds: - !Ref sg StorageCapacity: !Ref StorageCapacity StorageType: SSD # StorageType: HDD SubnetIds: !Ref SubnetIds WindowsConfiguration: # ActiveDirectoryId: !Ref ActiveDirectoryId AutomaticBackupRetentionDays: 7 CopyTagsToBackups: true DailyAutomaticBackupStartTime: !Ref DailyAutomaticBackupStartTime DeploymentType: !Ref DeploymentType # PreferredSubnetId: String SelfManagedActiveDirectoryConfiguration: DnsIps: !Ref OnpreDNS DomainName: !Ref OnpreDomainName FileSystemAdministratorsGroup: !Ref FileSystemAdministratorsGroup OrganizationalUnitDistinguishedName: !Ref OrganizationalUnitDistinguishedName Password: !Ref Password UserName: !Ref UserName ThroughputCapacity: !Ref ThroughputCapacity WeeklyMaintenanceStartTime: !Ref WeeklyMaintenanceStartTime sg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${EnvPrefix}-sg GroupName: !Sub ${EnvPrefix}-sg VpcId: !Ref VPCId SecurityGroupIngress: - CidrIp: !Ref FSXAllowedRange FromPort: 445 ToPort: 445 IpProtocol: tcp - CidrIp: !Ref FSXAllowedRange FromPort: 5985 ToPort: 5985 IpProtocol: tcp Tags: - Key: Name Value: FSX CloudWatchAlarmFreeStorageCapacity: Type: AWS::CloudWatch::Alarm Properties: ActionsEnabled: 'true' ComparisonOperator: LessThanOrEqualToThreshold EvaluationPeriods: '1' MetricName: FreeStorageCapacity Namespace: AWS/FSx AlarmName: !Sub ${EnvPrefix}FreeStorageCapacity Period: '300' Statistic: Average Threshold: !Ref ThresholdFreeStorageCapacity AlarmActions: - !Ref SNSNotif Dimensions: - Name: FileSystemId Value: !Ref fsx SNSNotif: Type: AWS::SNS::Topic Properties: DisplayName: !Sub ${EnvPrefix}Topic Subscription: - Endpoint: !Ref endpointEmail Protocol: email TopicName: !Sub ${EnvPrefix}TopicTicket
AWS fsx for windows (自己所有AD)の事前のAD設定メモ
FSXを自己所有のADで作成する際、AD側で何をすれば良いのかが AWSのドキュメントを見ても、いまいち分かりにくかったです。 docs.aws.amazon.com aws.amazon.com 上記を見ながら作業をしてみたところ正常動作でき、 作業をより分かりやすく残しておきたいと思い、 備忘メモとしてブログ化します。
ADの事前設定
ADでOU、グループ、ユーザを作成
まず、AD側の手順として、下記を作成します。
設定項目 | 設定値 |
---|---|
OU | FileSystems |
UserName | fsxservice |
FileSystemAdministratorsGroup | FSXAdmins |
Password | 適当 |
「dsa.msc」を開く OUを「FileSystems」で作成します。
FileSystemsの中にユーザ、グループを作成します
その後、上記で作成したOUに権限を移譲します。
作成したOUで右クリックDelegate Controlを選択
「FSXAdmins」を指定
「Create a custom task to delegate」を選択します。
「Only the following objects in the folder」を選択し
「Computer objects」を選択します。
下記2つを選択します。
「Create selected objects in this folder」
「Delete selected objects in this folder」
さらに次の画面で下記を選択します。
- Reset Password
- Read and write Account Restriction
- Validated write to DNS host name
- Validated write to service principal name
以上でAD側の作業は完了です。
fsxを作成する
上記が作成できましたら、fsxを作成します。 cloudformationを作りました。
AWSTemplateFormatVersion: "2010-09-09" Description: A templete for fsx for windows Parameters: EnvPrefix: Type: String Default: "test" # KmsKeyId: # Type: String StorageCapacity: Type: Number Default : 32 VPCId: Type: AWS::EC2::VPC::Id Default: vpc-xxxxxxxxxxx SubnetIds: Type: List<AWS::EC2::Subnet::Id> Default: subnet-xxxxxxxxxxx DailyAutomaticBackupStartTime: Type: String Default: "16:00" DeploymentType: Type: String Default: SINGLE_AZ_2 # Default: MULTI_AZ_1 ThroughputCapacity: Type: Number Default : 8 WeeklyMaintenanceStartTime: Type: String Default: "6:17:00" OnpreDNS: Type: CommaDelimitedList Default: xxx.xxx.xxx.xxx OnpreDomainName: Type: String Default: fsx-test.local FileSystemAdministratorsGroup: Type: String Default: FSXAdmins UserName: Type: String Default: fsxservice #本当はパラメータストア等を参照するのが良いです Password: Type: String Default: xxxxxxxxxxxxxx NoEcho: True OrganizationalUnitDistinguishedName: Type: String Default: "OU=FileSystems,DC=fsx-test,DC=local" FSXAllowedRange: Type: String Default: xx.xx.xx.xx/xx Resources : fsx: Type: AWS::FSx::FileSystem Properties: # BackupId: String # KmsKeyId: kms # LustreConfiguration: # LustreConfiguration FileSystemType: WINDOWS SecurityGroupIds: - !Ref sg StorageCapacity: !Ref StorageCapacity StorageType: SSD # StorageType: HDD # The StorageCapacity specified is not supported. Storage capacity for HDD must be no less than 2000 SubnetIds: !Ref SubnetIds WindowsConfiguration: # ActiveDirectoryId: !Ref ActiveDirectoryId AutomaticBackupRetentionDays: 7 CopyTagsToBackups: true DailyAutomaticBackupStartTime: !Ref DailyAutomaticBackupStartTime DeploymentType: !Ref DeploymentType # PreferredSubnetId: String SelfManagedActiveDirectoryConfiguration: DnsIps: !Ref OnpreDNS DomainName: !Ref OnpreDomainName FileSystemAdministratorsGroup: !Ref FileSystemAdministratorsGroup OrganizationalUnitDistinguishedName: !Ref OrganizationalUnitDistinguishedName Password: !Ref Password UserName: !Ref UserName ThroughputCapacity: !Ref ThroughputCapacity WeeklyMaintenanceStartTime: !Ref WeeklyMaintenanceStartTime sg: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: !Sub ${EnvPrefix}-sg GroupName: !Sub ${EnvPrefix}-sg VpcId: !Ref VPCId SecurityGroupIngress: - CidrIp: !Ref FSXAllowedRange FromPort: 445 ToPort: 445 IpProtocol: tcp - CidrIp: !Ref FSXAllowedRange FromPort: 5985 ToPort: 5985 IpProtocol: tcp Tags: - Key: Name Value: FSX