継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

Datadog で NO DATA ステータスを通知するオプションを調べた

タダです.

Datadog を監視として使っているのですが,監視として集めているデータが上がってこない時に NO DATA となりアラートも発報しなかったりと監視に置いて困る状況になります.そこで,NO DATA になっているものがあったら通知するようにする方法を調べたのでこの記事に備忘録としてまとめます.

NO DATA の通知方法

ドキュメントに記載のように NO DATA が続く場合は監視の設定から通知を指定することができます.

データなしを通知しない場合は Do not notify を、データなしが N 分以上続いた時に通知する場合は Notify を設定します

docs.datadoghq.com

Terraform での設定方法

Terraform で NO DATA を通知する方法を調べたところ notify_no_data を使うことで設定できます.

notify_no_data (Boolean) A boolean indicating whether this monitor will notify when data stops reporting. Defaults to false.

notify_no_data = true

registry.terraform.io

まとめ

Datadog の NO DATA を通知する方法を調べたのを整理するためにまとめました.Datadog まだまだ初心者なため知見はためていくために記事を書いていければと思います.

条件ごとで Terraform によるリソース作成を行う

タダです.

ここ最近は Terraform で学ぶことが多いため,今回もそんな記事です.今回は例えば,開発であればリソースを作らないやパラメーターを変える,本番であればこのパラメーターをセットするといった条件に応じたリソース作成を行うための小ネタを学んだので,備忘録として記事に残しておきます.

1, 環境ごとにリソースのパラメーターを分ける

例えば,コストの観点から開発環境はマシンスペックを小さくし,本番環境はマシンスペックを大きくして作りたいって事はあると思います.そんな時に役立つのが下記のような書き方です.変数 env として dev が指定されたら t3.micro を,それ以外は m5.large を分けるという動作になります.

resource "aws_instance" "hoge" {
  instance_type = var.env == "dev" ? t3.micro : m5.large
}

関連情報

www.terraform.io

2, 特定条件でリソースの作成する/しないを指定する

システム運用中に開発環境ならリソースは不要だけど,本番は必要だから作りたいって要望はあると思います.上記の環境ごとにリソース作成のパラメーターを分ける手法を使って,countで変数 env として dev が指定されたらリソースが作られず,それ以外のパラメータが指定されたらリソースを作るという動作を制御できます.

count = var.env == "dev" ? 0 : 1

関連情報

www.terraform.io

まとめ

小ネタになりますが,条件に応じたリソース作成の記述をまとめました.Terraform との付き合いは増えそうなので,学んだことをまた書いていきたいと思います.

参照記事

qiita.com

cloud-textbook.com

Terraform の差分を解消するためにローカルで tfstate を修正する

タダです.

やったことないオペレーションで S3 で管理している Terraform の tfstate をローカルで変更する作業を経験したので備忘録として記事に残しておきます.

前提

そもそもなぜ tfstate をいじることになったのかというと,Terraform のコードと管理している AWS 環境で差分が発生したため,terraform import を行う必要があったからです.S3 に tfstate が入っているんだから直接いじることも可能だと思いますが,万が一誤ったリソースの情報を消してしまったりすると大変なためローカルでの tfstate の変更を行うことにしました.

手動で変更してしまったリソースが terraform plan で差分として出たイメージ

# aws_subnet.hoge_subnet will be updated in-place
  ~ resource "aws_subnet" "hoge_subnet" {
        id                                             = "subnet-123456789101112"
      ~ tags                                           = {
          - "test"  = "hoge" -> null
            # (2 unchanged elements hidden)
        }
      ~ tags_all                                       = {
          - "test"  = "hoge" -> null
            # (2 unchanged elements hidden)
        }
        # (14 unchanged attributes hidden)
    }

行ったオペレーション

1,tfstate をローカルに持ってくる

terraform init 後にまずは手元に tfstate を持ってきます.terraform state pull を使って,アウトプットで別ファイルに書き出します.

❯❯❯ terraform state pull > hoge.tfstate

その後,provider の設定を書いているファイルを編集し,backend "s3" のセクションをコメントアウトし,terraform init で作成された .terraform.lock.hcl.terraform ディレクトリを削除します.

terraform {
  required_version = ">= 1.0.0"

  # backend "s3" {
  #   ~中略~
  # }

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = ">= 3.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

その後,再度 terraform init を実行できたらローカルで tfstate を変更できるようになったので差分を埋めることができます.

❯❯❯ terraform init                                           

Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching ">= 3.0.0"...
- Installing hashicorp/aws v4.5.0...
- Installed hashicorp/aws v4.5.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

2,tfstate を編集する

まずは terraform state showterraform import する対象の状態を確認します.差分として出ている test タグもない状態なので,これをいじって差分を埋めていきます.

❯❯❯ terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet 
# aws_subnet.hoge_subnet:
resource "aws_subnet" "hoge_subnet" {
    arn                                            = "arn:aws:ec2:ap-northeast-1:123456789101112:subnet/subnet-123456789101112"
    assign_ipv6_address_on_creation                = false
    availability_zone                              = "ap-northeast-1a"
    availability_zone_id                           = "apne1-az4"
    cidr_block                                     = "10.0.0.0/24"
    enable_dns64                                   = false
    enable_resource_name_dns_a_record_on_launch    = false
    enable_resource_name_dns_aaaa_record_on_launch = false
    id                                             = "subnet-123456789101112"
    ipv6_native                                    = false
    map_customer_owned_ip_on_launch                = false
    map_public_ip_on_launch                        = true
    owner_id                                       = "123456789101112"
    private_dns_hostname_type_on_launch            = "ip-name"
    tags                                           = {
        "Name"  = "hoge-subnet"
        "Owner" = "tada"
    }
    tags_all                                       = {
        "Name"  = "hoge-subnet"
        "Owner" = "tada"
    }
    vpc_id                                         = "vpc-123456789101112"
}

次に terraform state rm で対象リソースの state を消します.この後,ローカルの tfstate の中から削除したリソースデータがなくなっているはずです.

❯❯❯ terraform state rm -state=hoge.tfstate aws_subnet.hoge_subnet
Removed aws_subnet.hoge_subnet
Successfully removed 1 resource instance(s).

そして, terraform import で対象リソースを取り込んでコード側も差分が出ている tag を追記した後,terraform state showterraform plan の実行計画を見て差分がないことを確認できるはずです.ここまでで tfstate をいじる作業は終わりです.

❯❯❯  terraform import -state=hoge.tfstate aws_subnet.hoge_subnet subnet-123456789101112
aws_subnet.hoge_subnet: Importing from ID "subnet-123456789101112"...
aws_subnet.hoge_subnet: Import prepared!
  Prepared aws_subnet for import
aws_subnet.hoge_subnet: Refreshing state... [id=subnet-123456789101112]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet 

❯❯❯ terraform state show -state=hoge.tfstate aws_subnet.hoge_subnet 
# aws_subnet.hoge_subnet:
resource "aws_subnet" "hoge_subnet" {
    arn                                            = "arn:aws:ec2:ap-northeast-1:123456789101112:subnet/subnet-123456789101112"
    assign_ipv6_address_on_creation                = false
    availability_zone                              = "ap-northeast-1a"
    availability_zone_id                           = "apne1-az4"
    cidr_block                                     = "10.0.0.0/24"
    enable_dns64                                   = false
    enable_resource_name_dns_a_record_on_launch    = false
    enable_resource_name_dns_aaaa_record_on_launch = false
    id                                             = "subnet-123456789101112"
    ipv6_native                                    = false
    map_customer_owned_ip_on_launch                = false
    map_public_ip_on_launch                        = true
    owner_id                                       = "123456789101112"
    private_dns_hostname_type_on_launch            = "ip-name"
    tags                                           = {
        "Name"  = "hoge-subnet"
        "Owner" = "tada"
        "test"  = "hoge"
    }
    tags_all                                       = {
        "Name"  = "hoge-subnet"
        "Owner" = "tada"
        "test"  = "hoge"
    }
    vpc_id                                         = "vpc-123456789101112"
}
❯❯❯ terraform plan -state=hoge.tfstate

3,リモートの tfstate にローカルの変更を反映する

最後にローカルで変更した tfstate をリモート側に反映します.tfstate をローカルに持ってくるときにコメントアウトした backend "s3" のセクションを戻し, .terraform.lock.hcl.terraform ディレクトリを削除して terraform init します.backend "s3"になっています.

❯❯❯ terraform init  

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Finding hashicorp/aws versions matching ">= 3.0.0"...
- Installing hashicorp/aws v4.5.0...
- Installed hashicorp/aws v4.5.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

最後に,terraform state pushでリモートの tfstate に反映します.コマンド実行後,リモートの tfstate がコマンド実行時間帯で更新されているはずです.そして,この状態で terraform planで実行計画を確認するとローカルで確認した結果と同じになっていれば目的の作業は完了です.

❯❯❯ terraform state push hoge.tfstate

まとめ

リモートの tfstate をいじらずに安全に反映していくための作業を経験したので,やった作業をまとめました.初めてのオペレーションでわからないことが多い中,下記の参考記事をベースに対応したので大変助かりました...

参考記事

qiita.com

カスタムルールを設定して Terraform のコードを tfsec で解析する

タダです.

業務の中で tfsec を使う機会があり,tfsecを使って,デフォルトのルールにない条件で解析を行うような仕組み化をやったのでこの記事でどういうことをやったのかをまとめていきます.

github.com

tfsec とは

tfsec は Aqua Security 社が開発している Terraform の静的セキュリティチェックを行い,潜在的なセキュリティ脅威を分析するのに寄与するツールです.

tfsec uses static analysis of your terraform templates to spot potential security issues. Now with terraform CDK support.

tfsec の導入

tfsecbrew で導入できます.その他の方法についてはこちらを参照ください.また,コンテナイメージも提供されています.

❯❯❯ brew install tfsec

tfsec のオプションとして次のものがあります.基本的なコマンドは tfsec . で実行できます.

❯❯❯ tfsec --help                                                                              
tfsec is a simple tool to detect potential security vulnerabilities in your terraformed infrastructure.

Usage:
  tfsec [directory] [flags]

Flags:
      --concise-output               Reduce the amount of output and no statistics
      --config-file string           Config file to use during run
      --custom-check-dir string      Explicitly the custom checks dir location
      --debug                        Enable debug logging (same as verbose)
  -G, --disable-grouping             Disable grouping of similar results
  -e, --exclude string               Provide comma-separated list of rule IDs to exclude from run.
      --exclude-downloaded-modules   Remove results for downloaded modules in .terraform folder
      --exclude-path strings         Folder path to exclude, can be used multiple times and evaluated in order of specification
      --filter-results string        Filter results to return specific checks only (supports comma-delimited input).
      --force-all-dirs               Don't search for tf files, include everything below provided directory.
  -f, --format string                Select output format: default, json, csv, checkstyle, junit, sarif. To use multiple formats, separate with a comma and specify a base output filename with --out. A file will be written for each type. The first format will additionally be written stdout.
  -h, --help                         help for tfsec
      --ignore-hcl-errors            Stop and report an error if an HCL parse error is encountered
      --include-ignored              Include ignored checks in the result output
      --include-passed               Include passed checks in the result output
      --migrate-ignores              Migrate ignore codes to the new ID structure
      --no-color                     Disable colored output (American style!)
      --no-colour                    Disable coloured output
  -O, --out string                   Set output file. This filename will have a format descriptor appended if multiple formats are specified with --format
      --run-statistics               View statistics table of current findings.
      --single-thread                Run checks using a single thread
  -s, --soft-fail                    Runs checks but suppresses error code
      --tfvars-file strings          Path to .tfvars file, can be used multiple times and evaluated in order of specification
      --update                       Update to latest version
      --verbose                      Enable verbose logging (same as debug)
  -v, --version                      Show version information and exit
  -w, --workspace string             Specify a workspace for ignore limits (default "default")

tfsec で提供されているチェックのルールセットには次のものがあり,どのようなチェックを行っているかはこのページから確認できます.今回は AWS Checks を使います.

tfsec 実行

tfsec 導入後に,試しに AWS の Terraform コードのディレクトリで tfsec . で実行してみると,tfsecのルールセットから違反したコードの箇所が指摘されて出力されます.出力結果から組織的に無視していいものや要対応のものを整理していくことになると思います.無視するときは個別のコードの中で無視するものを設定します.

tfsec .                                                              

Results #1-2 CRITICAL Security group rule allows egress to multiple public internet addresses. (2 similar results)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 hoge/xx.tf Line 41
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   37  │   egress {
   38  │     from_port   = 0
   39  │     to_port     = 0
   40  │     protocol    = "-1"
   41  │     cidr_blocks = ["0.0.0.0/0"]
   42}
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  Individual Causes
  - /Users/tady/hoge/xx.tf:25-47 (xxx.xx)
  - /Users/tady/hoge/xx.tf:1-6 (xxx.xx)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          ID aws-vpc-no-public-egress-sgr
      Impact Your port is egressing data to the internet
  Resolution Set a more restrictive cidr range

  More Information
  - https://aquasecurity.github.io/tfsec/v1.6.2/checks/aws/vpc/no-public-egress-sgr/
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

~中略~

  timings
  ──────────────────────────────────────────
  disk i/o             6.723876ms
  parsing              15.561457ms
  adaptation           2.028416ms
  checks               4.20521ms
  total                28.518959ms

  counts
  ──────────────────────────────────────────
  blocks               108
  modules              5
  files                46

  results
  ──────────────────────────────────────────
  ignored              0
  excluded             0
  critical             6
  high                 15
  medium               2
  low                  14

  37 potential problem(s) detected.

カスタムルールを作って GitHub Actions でチェックする

組織的にルールセットにないけどチェックしたい定義があったらカスタムルールを作って解析します..tfsecディレクトリを作り,_tfchecks.yaml_tfchecks.json を置いてくとチェックしてくれます.今回は,Terraform で管理されているリソースに必ず terraform タグを付けるようにチェックするルールにしました.

---
checks:
- code: CUS001
  description: Check if the terraform tag set for all supported resources.
  errorMessage: The required terraform tag was missing
  matchSpec:
    action: contains
    name: tags
    value: terraform
  requiredTypes:
  - resource
  requiredLabels:
  - aws_*
  severity: ERROR 

加えて GitHub Actions でプルリクエストが上がってきたときに編集したリソースが違反しているかチェックするよう reviewdog/action-tfsec で仕組み化してみます.

name: tfsec
on:
  pull_request:

jobs:
  tfsec:
    runs-on: ubuntu-latest

    steps:
      - name: checkout
        uses: actions/checkout@v3

      - name: Run tfsec with reviewdog 
        uses: reviewdog/action-tfsec@master
        with:
          github_token: ${{ secrets.github_token }}
          level: info
          working_directory: my_directory
          reporter: github-pr-review 
          fail_on_error: true
          filter_mode: nofilter

関連情報

aquasecurity.github.io

テスト実行

テスト実行をしたいので試しに セキュリティグループを追加するようなコードを書いてプルリクエストを出したとします.この状態だと terraform タグがないのでチェックに上がってきます.これでプルリクエストの段階で組織的にチェックしたいルールを仕組み化していけそうです.

resource "aws_security_group" "ecr_vpcendpoint_sg" {
  name   = "ecr-vpc-endpoint-sg"
  vpc_id = aws_vpc.tf_vpc.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.tf_vpc.cidr_block]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
      Name = "ecr-vpc-endpoint-sg"
  }
}

プルリクエストでチェックされたときの例

f:id:sadayoshi_tada:20220306152235p:plain

まとめ

tfsec のカスタムチェックで組織的にルール化したいことを定義してみました.こういったガバナンスを効かせて統一的なチェックを行うのは人力では難しいと思うので,こういった仕組み化をしていけると長期的に見て良さそうだと感じました.

リポジトリに載せたくない秘匿情報をチェックする Secretlint を触った

タダです.

リポジトリAWS のアクセスキー,シークレットアクセスキーを載せてしまって情報の漏洩といったことが起こりうるので,その予防策としてSecretlintを触る機会があったためこの記事に備忘録をまとめます.

Secretlint とは

Secretlintazu さんが開発されている秘匿情報のコミットを防ぐツールです.

github.com

Secretlint 導入

Docker イメージも提供されていますが,今回は npm で導入し,npx secretlint --initSecretlint の設定ファイルを生成します.

$ npm install secretlint @secretlint/secretlint-rule-preset-recommend --save-dev

added 276 packages, and audited 277 packages in 24s

36 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
$ npx secretlint --init
Create .secretlintrc.json

.secretlintrc.json という設定ファイルを開くと推奨ルールセット(@secretlint/secretlint-rule-preset-recommend)が設定されています.

{
  "rules": [
    {
      "id": "@secretlint/secretlint-rule-preset-recommend"
    }
  ]
}

Secretlint のルール

推奨ルールセットの他に個別のルールセットが以下のものがあります.

  • @secretlint/secretlint-rule-npm
  • @secretlint/secretlint-rule-aws
  • @secretlint/secretlint-rule-gcp
  • @secretlint/secretlint-rule-github
  • @secretlint/secretlint-rule-privatekey
  • @secretlint/secretlint-rule-basicauth
  • @secretlint/secretlint-rule-slack
  • @secretlint/secretlint-rule-sendgrid
  • @secretlint/secretlint-rule-secp256k1-privatekey
  • @secretlint/secretlint-rule-no-k8s-kind-secret
  • @secretlint/secretlint-rule-pattern
  • @secretlint/secretlint-rule-no-homedir
  • @secretlint/secretlint-rule-no-dotenv

例えば,@secretlint/secretlint-rule-awsでは AWS アカウント番号,アクセスキー,シークレットアクセスキーが書かれていないかをチェックしてくれます.また無視したい条件をチェック対象から外したりすることも可能です.

Secretlint を実行する

意図的に .env ファイルに AWS アクセスキー,シークレットアクセスキーを設定してSecretlintを実行してみました.@secretlint/secretlint-rule-awsのルールに引っかかっています.このようにチェックができるため,自分だけでなくプロジェクトで設定しておくと誤って GitHub に載せちゃうってことが防げるためガードレールになると思います.

$ npx secretlint "**/*"

/Users/tady/xxx/github.com/tasogare0919/xxx/.env
  1:18  error  [AWSAccessKeyID] found AWS Access Key ID: hoge                              @secretlint/secretlint-rule-preset-recommend > @secretlint/secretlint-rule-aws
  2:0   error  [AWSSecretAccessKey] found AWS Secret Access Key: hoge  @secretlint/secretlint-rule-preset-recommend > @secretlint/secretlint-rule-aws

✖ 2 problems (2 errors, 0 warnings)

azu さんが記事でも紹介されていますが, このツールを使って git-hooks や CI でチェックを仕組み化していきたいです.

git-hooks 実行例

 git commit -m "test commit"
  ▶ Check credentials by secretlint
Unable to find image 'secretlint/secretlint:latest' locally
latest: Pulling from secretlint/secretlint
59bf1c3509f3: Pull complete 
f1265917d930: Pull complete 
550febb8ed3d: Pull complete 
8a58962111ca: Pull complete 
ddf315adcbfd: Pull complete 
93f101a4cc21: Pull complete 
Digest: sha256:916807d43cff2d6927a62ac588594ab4322e28ad8cce31410b3b392e1762c483
Status: Downloaded newer image for secretlint/secretlint:latest
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

/Users/tady/xxx/github.com/tasogare0919/xxx/.env
  1:18  error  [AWSAccessKeyID] found AWS Access Key ID: hoge                              @secretlint/secretlint-rule-preset-recommend > @secretlint/secretlint-rule-aws
  2:0   error  [AWSSecretAccessKey] found AWS Secret Access Key: hoge  @secretlint/secretlint-rule-preset-recommend > @secretlint/secretlint-rule-aws

✖ 2 problems (2 errors, 0 warnings)

GitHub Actions で秘匿情報を push でチェックした場合の例

f:id:sadayoshi_tada:20220220172946p:plain

まとめ

Secretlintを触った備忘録を記事にまとめていきました.初めて触ってみて導入の敷居がかなり低く始められるという印象で,セキュリティ向上のために個人環境でもいれていきたいと感じました.

参考情報

efcl.info