CloudFormation を使用することで、AWS のリソースを素早くプロビジョニングできます。また、yaml 形式のテンプレートファイルで記述することにより、インフラ開発者はどのリソースが作成されるのかを宣言的に管理できます。
開発者は AWS リソースをすばやく簡単に作成できますが、安全でないリソースもすばやく作成できてしまいます。「安全でない」とは、TCP ポートを世界中に公開したり、特定の IAM ユーザーにフル権限を与えてしまうことでセキュリティ的に問題があるリソースを作り出してしまうことを意味しています。
以前、CircleCI MeetUp で CloudFormation を静的構文解析する話をしました。
CloudFormation を静的構文解析することにより、セキュリティ的に問題があったり、命名規則に従っていないリソースに対して警告できます。このようにポリシー違反を検知する仕組みを作ることで、AWS リソースを構築する前にセキュリティ的な問題を対応できるようになります。
ただしルールを全て自作したり、セキュリティ的に問題がある箇所を洗い出す作業は非常に面倒です。
今回はそんなケースに有効な cfn-nag というツールを紹介します。
cfn-nag はセキュリティ的に問題がある CloudFormation のテンプレートを警告できるツールです。cfn-Python-lint と並んで CI のプロセスに組み込むことができます。
cfn-nag のインストール
cfn-nag は Ruby 製のツールです。Gem としてインストールしましょう。
gem install cfn-nag
cfn-nag の使用方法
以下のようなテンプレートを例に取り上げます。
外部から 80 番ポートで TCP 通信することを許可するセキュリティグループを作成しようとしています。
SecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
VpcId: !Ref VpcId
GroupDescription: security group
SecurityGroupIngress:
- IpProtocol: "TCP"
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: "All"
このテンプレートに対して cfn-nag を実行してみましょう。
$ cfn_nag template.yaml
------------------------------------------------------------
template.yaml
------------------------------------------------------------------------------------------------------------------------
| WARN W9
|
| Resources: ["SecurityGroup"]
| Line Numbers: [9]
|
| Security Groups found with ingress cidr that is not /32
------------------------------------------------------------
| WARN W2
|
| Resources: ["SecurityGroup"]
| Line Numbers: [9]
|
| Security Groups found with cidr open to world on ingress. This should never be true on instance. Permissible on ELB
------------------------------------------------------------
| FAIL F1000
|
| Resources: ["SecurityGroup"]
| Line Numbers: [9]
|
| Missing egress rule means all traffic is allowed outbound. Make this explicit if it is desired configuration
Failures count: 1
Warnings count: 2
2つの Warnings, 1 つの Failure, 合計 3 つの警告がでました。
- Warnings: ingress ルールで/32 からのアクセスを許可していること
- Warnings: ingress ルールが全世界に向けて全開放していること
- Failures: egress ルールがついていないこと
cfn-nag のルールを許容する
cfn-nag の警告を確認すると確かにセキュリティ的にはあまりよくないルールになっていますね。
ただし、実際にこのようなセキュリティグループを使用することはよくあります。たとえばチームとして egress ルールは全許可にしていても良いなどのルールを決めている。あるいはパブリックユーザ向けの Web サービスの場合、特定のポート番号(例えば 443)で ingress ルールを全世界に向けて全開放することは一般的です。
このような場合は、許容するルールを Metadata
に記載しておきましょう。
SecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: !Ref VpcId
GroupDescription: security group
SecurityGroupIngress:
- IpProtocol: "TCP"
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: "All"
Metadata:
cfn_nag:
rules_to_suppress:
- id: W9
reason: "このセキュリティグループはEC2には付与しない。ELBに付与して使用する"
- id: W2
reason: "このセキュリティグループはEC2には付与しない。ELBに付与して使用する"
- id: F1000
reason: "egressルールには制限を課しません"
このようにしておくことで警告を無視できます。
$ cfn_nag template.yaml
------------------------------------------------------------
template.yaml
------------------------------------------------------------
Failures count: 0
Warnings count: 0
開発環境に組み込む(VSCode の場合)
VSCode には cfn-nag の拡張機能(プラグイン)が提供されています。
こちらからインストールしておきましょう。
Format On Save
の項目にチェックを入れておくと、ファイルを保存した時に自動的に cfn-nag が実行されます。
このようにすることで早い段階でセキュリティ的に問題があるテンプレートを見つけることができるようになりました。
CI に組み込む(CircleCI の場合)
さらにCIのプロセスにも組み込んでおくと安心です。CircleCI の場合は以下のような感じでしょうか。
実際のユースケースに合わせて bundler
で管理することもあるかと思います。
version: 2
jobs:
build:
docker:
- image: circleci/ruby:2.6.0-node-browsers-legacy
working_directory: ~/repo
steps:
- checkout
- run: gem install cfn-nag
- run: cfn_nag template.yaml