Safie Engineers' Blog!

Safieのエンジニアが書くブログです

driftctlによるIaC化推進に向けた取り組み

こんにちは。セーフィー株式会社 バックエンドエンジニアの村田 (@naofumimurata)です。

この記事はセーフィー株式会社 Advent Calendar 2022 の12月15日の記事です!

本記事ではセーフィーにおけるdriftctlというツールを活用したIaC化推進に向けた取り組みについてご紹介したいと思います。

セーフィーのインフラ環境と課題

セーフィーではインフラ環境としてAWSを利用しており、Terraform を利用してAWSリソースのコード管理を行なっています。基本的に新しく作られるものについてはTerraformで構築されるのでコード管理された状態になっているのですが、歴史的経緯(後からTerraformが導入された)によりコード管理できていないリソースがまだ残ってしまっているという課題があります。

また、そういったコード管理されていないリソースを見つけるには、Terraformコードベースの知識とセーフィーのインフラ構成の両方の知識が必要であるため、対応できる人がやるというような形になり中々コード化が進まないという課題もありました。

driftctlとは

前述のような課題の解決に役立ちそうなツールとして driftctl というものがあります。 https://github.com/snyk/driftctl

driftctlはクラウド上のリソースとIaC (Infrastructure as Code) コードを比較し以下のリソースを検知することができます。

  • IaC管理されていないリソース
  • IaC管理されているが実際の状態と差分が出てしまっているリソース

本記事の執筆現在 (2022/12/15) 、最新バージョンは v0.38.1 で、IaCツールは Terraformのみをサポートしており、クラウドプロバイダとしては AWS, GitHub, Azure, GCPをサポートしています。

また、READMEには以下の記載があり、まだbeta版であるということが注意書きされています。

⚠️ This tool is still in beta state and will evolve in the future with potential breaking changes ⚠️

driftctlの使い方

準備

まず、以下を参考にインストールを行います。 https://docs.driftctl.com/0.38.0/installation

その後、利用するクラウドプロバイダの認証情報を有効にします。 https://docs.driftctl.com/0.38.0/providers/aws/authentication

スキャンの実行

以下のコマンドを実行するとスキャンが実施されます。

$ driftctl scan

特にオプションを指定しない場合、カレントディレクトリのHCLファイルから利用しているtfstateを検出し読み込みます。HCLファイルからtfstateの検出に失敗した場合、ローカルの terraform.tfstate ファイルを読み込もうとします。

tfstateを指定したい場合は --from オプション (環境変数で指定する場合は DCTL_FROM) で指定することができます。

$ driftctl scan --from tfstate+s3://tfstate-bucket/terraform.tfstate

ワイルドカードで複数tfstateをまとめて指定することもできます。

$ driftctl scan --from tfstate+s3://tfstate-bucket/*.tfstate

無事にスキャンが終わると、以下の様に結果がコンソールに出力されます。

Found missing resources:
  aws_s3_bucket:
    - test-bucket-1
Found resources not covered by IaC:
  aws_s3_bucket:
    - test-bucket-2
Found changed resources:
  - test-bucket-3 (aws_s3_bucket):
    ~ Versioning.0.Enabled: false => true
Found 3 resource(s)
 - 33% coverage
 - 1 covered by IaC
 - 1 not covered by IaC
 - 1 missing on cloud provider
 - 1/1 changed outside of IaC

結果の内容は以下の様になっています。

  • IaC管理下のリソースに対するスキャン結果
    • IaCコードには存在するが実際のクラウド上には存在しないリソースの一覧
    • IaCコードと実際のクラウド上の設定で差分が出てしまっているリソースの一覧と差分
  • IaC管理されているリソースに対するスキャン結果
    • IaC管理されていないリソースの一覧
  • 統計情報
    • カバレッジなど

出力形式の変更

デフォルトではスキャン結果はコンソールに出力されますが、--output オプション (環境変数: DCTL_OUTPUT) で出力形式を変更することができます。現在、利用できる出力形式はデフォルトのコンソール出力の他にJSON, HTMLがあります。

$ driftctl scan --output json://result.json
$ driftctl scan --output html://output.html

--only-managed オプション (環境変数: DCTL_ONLY_MANAGED) を指定することで、IaC管理下のリソースに対するスキャン結果だけを出力させるができます。

$ driftctl scan --only-managed

逆に IaC管理されていないリソースに対するスキャン結果のみを出力したい場合は --only-unmanaged オプション (環境変数: DCTL_ONLY_MANAGED) を指定します。

$ driftctl scan --only-unmanaged

.driftignoreファイルによるスキャン対象からの除外

driftctlでは特定のリソースをスキャン対象から除外させる機能があり、ファイルに以下のような形式で除外パターンを記述しておくとスキャン対象から外すことができます。

除外パターンを記載しておくファイルは、デフォルトで .driftignore という名前のファイルが使われますが、オプションでファイル指定ができるので別の名前でも問題ありません。

aws_s3_bucket.test
aws_instance.*

上記の除外パターンの意味としては、testという名前のAWS S3バケットとAWS EC2インスタンスの全リソースを除外するという意味になります。

以上で、driftctlの基本的な使い方の紹介を終わります。

他のオプションや詳しい使い方については公式ドキュメントをご参照ください。 https://docs.driftctl.com/0.38.0/usage/

GitHub Actions による定期実行

実際にdriftctlを使ってスキャンした結果を元に改善を進めていく場合、定期的に改善の状況をチームで確認していく必要があるかと思います。都度、誰かがスキャンを実行して結果を共有するのでも良いですが、自動で実行できる仕組みがあると便利かと思い GitHub Actions で定期実行するワークフローを導入しました。

セーフィーでは複数のAWSアカウントがありますが、試験的に導入したかったため、ひとまず1つのAWSアカウントを対象にスキャンを実施するようにしました。

name: driftctl
on:
  schedule:
    - cron:  '0 12 1 * *'
  workflow_dispatch:


jobs:
  driftctl:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: write
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          role-to-assume: ${{ secrets.ASSUME_ROLE_ARN }}
          aws-region: ap-northeast-1

      - name: Run
        uses: snyk/driftctl-action@v1
        continue-on-error: true
        env:
          DCTL_ONLY_UNMANAGED: true
          DCTL_OUTPUT: "html://report.html"
        with:
          version: 0.38.0

      - name: Chown
        run: sudo chown -R runner report.html

      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: Scan Report
          path: report.html

ワークフローの解説

ワークフローの内容は以下の通りです。

  • schedule トリガーイベントにより毎月月初に実行 or 手動起動で実行
  • AWS認証情報を有効にする
  • driftctl を実行
    • 公式のAction sync/driftctl-action を利用
    • 環境変数 DCTL_ONLY_UNMANAGED でIaC管理外のリソースに対する結果のみを出力するように指定
    • 環境変数 DCTL_OUTPUT でHTML形式で結果を出力するように指定
    • continue-on-error: true で失敗してもワークフローが続行されるように
  • 結果ファイルをartifactに保存

このワークフローをTerraformコードを管理しているリポジトリに設定し、月一でスキャンした結果をチームで確認、分担して調査とTerraform化を進めていく運用を開始しました。

取り組みの結果

現在、取り組みを始めてから数ヶ月経ちました。まだ全てのリソースのIaC化までは実現できていませんが、着々とカバレッジの数値が上がっており、引き続きこのまま取り組んでいきたいと思っています。

これまでは対応できる人が個人のモチベーションで対応していくという属人的な方法で改善していたものが、ツールを活用し誰でも確認し対応できる形にできたので、かなり進めやすくなりました。

driftctlを使ってみて

今回、driftctlというツールを使っていくなかで個人的に良いと感じた点、また、ちょっと気をつけて使わないといけない点があったので簡単にまとめたいと思います。

良い点

カバレッジが出せる

スキャン結果として、リソース全体のうちどのくらいIaC化できているかというカバレッジの値を出してくれるのですが、改善の状況を数値として確認できるのでとても便利です。

「何をコード管理しないか」をコード管理できる

.driftignore ファイルでスキャン対象から除外するリソースを指定できる機能もとても良いと思いました。リソースによってはあえてTerraformで管理していないものもあり(アプリケーションから作成されるリソースだったりGitHub PR環境用にCIから作られるリソースなど)、そういったリソースをスキャン対象が外せるとともに、「何をコード管理していないか」という情報をコード管理できるのが便利です。

気をつける必要がある点

リソースが多い環境だとrate limit 超過のエラーで失敗する

リソースが多い環境だとスキャンの途中でAWS APIのrate limit超過のエラーが発生し、スキャンに失敗してしまうことがあります。自分達の環境では、特にAWS Route53 Recordのリソースをスキャンしようとした場合にスキャンに失敗することが多かったため、不本意ながらスキャン対象から除外するように設定する必要がありました。この問題があるため、AWS APIを利用するアプリケーションが動く本番環境用のAWSアカウントなどで気軽にスキャンできないという別の問題も生まれています。

こちらの問題はissueとしても挙げられており、動向を注視しています。

https://github.com/snyk/driftctl/issues/1344

まとめ

今回は、driftctl というツールを活用したIaC化推進に向けた取り組みについてご紹介しました。driftctlはまだbeta版ということもあり、不足している機能もありますがとても便利なツールだと思うので興味を持たれた方はぜひ触ってみてください。取り組みを始めて数ヶ月経ち、まだ完全なIaC化までは実現できていませんが、着実に改善を進められていくことができています。本記事が同じような課題を持っている方の参考になれば幸いです。ここまで読んでいただき、ありがとうございました。

© Safie Inc.