TrivyでCloudFormationやTerraformのテンプレートを静的セキュリティスキャン可能になっていたので試してみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。枡川です。
Trivyをコンテナイメージの脆弱性スキャン時に便利なOSSと思っていたのですが、その認識は誤っていたようです。
イメージスキャンに加えて、CloudFormationやTerraformなどのIaC設定ファイルについてもセキュリティスキャンが可能になっていました。
Aqua SecurityからCloudFormation対応時のブログも出ています。

上記ブログの序文を引用すると、tfsecの技術とルールセットを使用してCloudFormationについても評価できるようになったようです。

Aqua Security’s open source project Trivy now includes scanning of AWS CloudFormation templates to help developers better identify and remediate security issues within infrastructure as code (IaC) templates. Building on the technology and rule sets behind our popular open source project tfsec, Trivy now allows developers to evaluate AWS CloudFormation code, either locally or within their pipeline, for configuration issues and violations of best-practice policies.

めちゃくちゃ便利そうなので試してみました!

Macでインストール

homebrewでインストールできます。

brew install aquasecurity/trivy/trivy

apt-getやyumでもインストールできます。
今回は2022年3月7日時点での最新版にあたるversion0.24.2を使用します。

やってみた

対象となる設定ファイルは下記4種類となります。

  • Terraform
  • CloudFormation
  • Kubernetes
  • Dockerfile

単純なS3+CloudFrontの構成を作成する下記のようなテンプレートを作成してスキャンを実行してみます。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  SystemName:
    Type: String
  EnvironmentName:
    Type: String
  CfSslCertificateId:
    Type: String

Resources:
  AssetsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub ${SystemName}-${EnvironmentName}-bucket
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  AssetsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AssetsBucket
      PolicyDocument:
        Statement:
          - Action: s3:GetObject
            Effect: Allow
            Principal:
              CanonicalUser: !GetAtt 'OriginAccessIdentity.S3CanonicalUserId'
            Resource: !Join
              - /
              - - !GetAtt 'AssetsBucket.Arn'
                - '*'
  Distribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        CustomErrorResponses:
          - ErrorCachingMinTTL: 30
            ErrorCode: 403
            ResponseCode: 200
            ResponsePagePath: /404.html
        DefaultCacheBehavior:
          ForwardedValues:
            QueryString: true
          TargetOriginId: !Sub 'S3-${AssetsBucket}'
          ViewerProtocolPolicy: redirect-to-https
        Aliases:
          - !Ref CfDomainName
        ViewerCertificate:
          AcmCertificateArn: !Sub "arn:aws:acm:us-east-1:${AWS::AccountId}:certificate/${CfSslCertificateId}"
          SslSupportMethod: sni-only
        DefaultRootObject: index.html
        Enabled: true
        HttpVersion: 'http2'
        Origins:
          - DomainName: !Sub '${AssetsBucket}.s3.amazonaws.com'
            Id: !Sub 'S3-${AssetsBucket}'
            S3OriginConfig:
              OriginAccessIdentity: !Sub 'origin-access-identity/cloudfront/${OriginAccessIdentity}'
  OriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: sample

設定ファイルのセキュリティスキャンを実行する際にはサブコマンドとしてconfigを使用します。(イメージスキャン時のサブコマンドはimageになっています。)

$ trivy config template.yml
2022-03-07T11:54:52.718+0900    INFO    Detected config files: 1

. (cloudformation)
==================
Tests: 14 (SUCCESSES: 7, FAILURES: 7, EXCEPTIONS: 0)
Failures: 7 (UNKNOWN: 0, LOW: 0, MEDIUM: 3, HIGH: 4, CRITICAL: 0)

+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
|             TYPE              |  MISCONF ID  |                  CHECK                   | SEVERITY |                 MESSAGE                  |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
| Cloudformation Security Check | AVD-AWS-0010 | Cloudfront distribution should have      |  MEDIUM  | Distribution does not have logging       |
|                               |              | Access Logging configured                |          | enabled.                                 |
+                               +--------------+------------------------------------------+----------+------------------------------------------+
|                               | AVD-AWS-0011 | CloudFront distribution does not have a  |   HIGH   | Distribution does not utilise a WAF.     |
|                               |              | WAF in front.                            |          |                                          |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0013 | CloudFront distribution uses outdated    |          | Distribution allows unencrypted          |
|                               |              | SSL/TLS protocols.                       |          | communications.                          |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0088 | Unencrypted S3 bucket.                   |          | Bucket does not have encryption enabled  |
+                               +--------------+------------------------------------------+----------+------------------------------------------+
|                               | AVD-AWS-0089 | S3 Bucket does not have logging enabled. |  MEDIUM  | Bucket does not have logging enabled     |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0090 | S3 Data should be versioned              |          | Bucket does not have versioning enabled  |
+                               +--------------+------------------------------------------+----------+------------------------------------------+
|                               | AVD-AWS-0132 | S3 encryption should use Customer        |   HIGH   | Bucket does not encrypt data with a      |
|                               |              | Managed Keys                             |          | customer managed key.                    |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+

7項目指摘されました。
Trivyでは、severityオプションを使用して表示する脆弱性を絞り込むことも可能です。
MEDIUMとLOWは一旦無視することにします。
ここで指定方法は表示するランクを全て指定する必要があります。
MEDIUMと指定したらMIDIUM以上はすべて表示とはなりません。

$ trivy config --severity HIGH,CRITICAL template.yml
2022-03-07T11:59:50.236+0900    INFO    Detected config files: 1

. (cloudformation)
==================
Tests: 10 (SUCCESSES: 6, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (HIGH: 4, CRITICAL: 0)

+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
|             TYPE              |  MISCONF ID  |                  CHECK                   | SEVERITY |                 MESSAGE                  |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
| Cloudformation Security Check | AVD-AWS-0011 | CloudFront distribution does not have a  |   HIGH   | Distribution does not utilise a WAF.     |
|                               |              | WAF in front.                            |          |                                          |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0013 | CloudFront distribution uses outdated    |          | Distribution allows unencrypted          |
|                               |              | SSL/TLS protocols.                       |          | communications.                          |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0088 | Unencrypted S3 bucket.                   |          | Bucket does not have encryption enabled  |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0132 | S3 encryption should use Customer        |          | Bucket does not encrypt data with a      |
|                               |              | Managed Keys                             |          | customer managed key.                    |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+

WAFを使った方が良いのはわかっているんだけどお金が無いんだ!という場合は.trivyignoreというファイルを作成して、特定の指摘を無視することも可能です。
検証目的でS3のCMKを使用した暗号化を設定するのも面倒だったので、S3の暗号化はCMKを使うべきという項目もついでに無効化しておきます。

$ (echo "AVD-AWS-0011"; echo "AVD-AWS-0132") > trivyignore
$ trivy config --severity HIGH template.yml
2022-03-07T14:28:45.370+0900    INFO    Detected config files: 1

. (cloudformation)
==================
Tests: 8 (SUCCESSES: 6, FAILURES: 2, EXCEPTIONS: 0)
Failures: 2 (HIGH: 2, CRITICAL: 0)

+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
|             TYPE              |  MISCONF ID  |                  CHECK                   | SEVERITY |                 MESSAGE                  |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
| Cloudformation Security Check | AVD-AWS-0013 | CloudFront distribution uses outdated    |   HIGH   | Distribution allows unencrypted          |
|                               |              | SSL/TLS protocols.                       |          | communications.                          |
+                               +--------------+------------------------------------------+          +------------------------------------------+
|                               | AVD-AWS-0088 | Unencrypted S3 bucket.                   |          | Bucket does not have encryption enabled  |
+-------------------------------+--------------+------------------------------------------+----------+------------------------------------------+

指摘事項が2個残りました。
各検出結果の修正方法は下記サイトに記載があります。

上記サイトにはセキュリティスキャンの内容についてもより詳細に説明があります。
推奨される書き方も記載されているので、CloudFormationに追加します。

CloudFrontのSSL/TLSプロトコルバージョンについても指摘されているので修正します。
マネコンから作成した場合は自然と推奨されているTLSv1.2_2021を選択しそうですが、MinimumProtocolVersionを指定せずにCloudFormationスタックを作成するとTLSv1になってますね。
この手の気づき辛い内容をチェックしてくれるのは有り難いです。
下記内容に従って修正します。
ここまでやって再度チェックをかけると、エラーが0個になりました。

$ trivy config --severity HIGH,CRITICAL template.yml
2022-03-07T14:29:59.662+0900    INFO    Detected config files: 1

. (cloudformation)
==================
Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (HIGH: 0, CRITICAL: 0)

ディレクトリを指定してスキャンを実施することで、当該ディレクトリにあるファイルを全て対象にすることが可能です。
DockerfileやKubernetesの定義ファイルについても同時にスキャンできます。

$ trivy config --severity HIGH,CRITICAL .
2022-03-07T14:32:44.905+0900    INFO    Detected config files: 3

Dockerfile (dockerfile)
=======================
Tests: 17 (SUCCESSES: 16, FAILURES: 1, EXCEPTIONS: 0)
Failures: 1 (HIGH: 1, CRITICAL: 0)

+---------------------------+------------+-----------+----------+------------------------------------------+
|           TYPE            | MISCONF ID |   CHECK   | SEVERITY |                 MESSAGE                  |
+---------------------------+------------+-----------+----------+------------------------------------------+
| Dockerfile Security Check |   DS002    | root user |   HIGH   | Specify at least 1 USER                  |
|                           |            |           |          | command in Dockerfile with               |
|                           |            |           |          | non-root user as argument                |
|                           |            |           |          | -->avd.aquasec.com/appshield/ds002       |
+---------------------------+------------+-----------+----------+------------------------------------------+

deployment.yml (kubernetes)
===========================
Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (HIGH: 0, CRITICAL: 0)


template.yml (cloudformation)
=============================
Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (HIGH: 0, CRITICAL: 0)

--skip-filesオプションを使用することで、Dockerfileのチェックを省いたりすることも可能です。

$ trivy config --severity HIGH,CRITICAL --skip-files Dockerfile .
2022-03-07T14:33:56.026+0900    INFO    Detected config files: 2

deployment.yml (kubernetes)
===========================
Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (HIGH: 0, CRITICAL: 0)


template.yml (cloudformation)
=============================
Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (HIGH: 0, CRITICAL: 0)

Terraformについてはtfsecを使用し続けるべきなのか、trivyを積極的に使用した方が良いのか難しいですね...
ローカルで実行する場合はtfsecコマンドを実行した際のレスポンスの方が下記のように詳細に記載されていて見やすい気がします。

Result #1 CRITICAL Listener for application load balancer does not use HTTPS. 
───────┬────────────────────────────────────────────────────────────────────────────────────────  
alb.tf Line 27
───────┬────────────────────────────────────────────────────────────────────────────────────────    
   24  │ resource "aws_lb_listener" "http" {
   25  │   load_balancer_arn = aws_lb.alb.arn
   26  │   port              = "80"
   27  │   protocol          = "HTTP"
   28  │ 
   29  │   default_action {
   30  │     type             = "forward"
   31  │     target_group_arn = aws_lb_target_group.ecs_target_group.arn
   32  │   }
   33  │ }
───────┬────────────────────────────────────────────────────────────────────────────────────────  
ID aws-elb-http-not-used
Impact Your traffic is not protected
Resolution Switch to HTTPS to benefit from TLS security features

一方、イメージスキャンで既にTrivyを使用している場合は使い方や出力が統一されているので使いやすいと思います。
cfsecのGithubは下記の記載がありますが、tfsecには特に書いていないので今までtfsecを使用している場合はそのままtfsecで良いのかなあという気もします。

The CloudFormation scanning logic is now integrated with Aquasecurity Trivy. cfsec will no longer be maintained as a stand alone scanner and Trivy should be used (引用)aquasecurity/cfsec

あくまで少し触ってみただけなので、何か明確な違い等が存在すればまたブログにしようと思います!

まとめ

サクッとインストールできて、イメージスキャンもDockerfileやCloudFormationの静的スキャンもいろんなことができるTrivyの凄さを改めて認識しました。
もっと使いこなして安全に開発していきたいですね!