ドクターズプライム Official Blog

「救急車たらい回しをゼロにする」ドクターズプライムの公式ブログです

Berglasを利用して安全にSecretを配布する

こちらはドクターズプライム Advent Calendar 2021の23日目の記事です。
昨日の記事はこちら

ドクターズプライム Advent Calendar 2021の23日目は、主森(@osamingo)が執筆させて頂きます。私は副業でSoftware Engineerとして働いています。(本業ではEngineering Managerをやっています。)

What is the Berglas?

Berglas logo

Berglasは、Goで作成されているGoogle Cloud Platform(以下、GCP)上でSecretsを保存および取得するためのCLI/Libraryです。Secretsの保存先には、Cloud KMS & Cloud Storageか、Secret Managerを利用することができます。

この記事では、Google App Engine (Go)での事例を紹介しますが、他のGCPサービスや言語でも利用することが可能です。詳しくは、公式のExampleを参照して下さい。

Berglasをなぜ使うのか

Dr.’s Primeでは、少し複雑なSecrets管理を行っていました。これらをシンプル且つ、よりセキュアにしたいという背景があります。既存の状態をある程度担保しつつ、少ないコストで実現する手法としてBerglasを利用することになりました。
今年においてはCodecovへの攻撃などもあり、Supply Chain AttackからSecretsを守るためにCI/CD Pipelineで環境変数を利用する機会を限りなくゼロに近付ける取り組みの一環でもあります。

As-Is

  • GitHub ActionsにてSecrets管理を行っている。
  • Deploy時にGitHub Actionsに登録されているSecretsを環境変数としてapp.yamlに追記し、Artifactsに加えている。

To-Be

  • Secret Managerを利用して、よりセキュアなSecrets管理と権限管理を行いたい。
  • アプリケーションの起動時に動的にSecretsを取得して、Secretsを参照しなければならない機会を減らしたい。

Berglasを使ってSecret ManagerにSecretsを登録する

Secret ManagerのAPI有効化

まずは、対象のGCP ProjectのSecret ManagerのAPIを利用できる状態にしなければいけません。Web Consoleから、GUIを使って有効化する方法がありますが、Dr.’s PrimeではTerraformを利用して有効化管理をしています。
Google Providerのgoogle_project_serviceを使うと有効化を定義することができます。

locals {
  services = toset([
    ...,
    "secretmanager.googleapis.com",
    ...,
  ])
}

resource "google_project_service" "project" {
  ...
  for_each = local.services
  service  = each.value
}

Berglasをインストールする

BerglasをCLIとして開発環境にインストールをします。BerglasのRepositoryに設置してあるREADMEでもいくつか方法が書かれていますが、Dr.’s Primeの場合はGoで開発していることもありTool dependenciesとして管理しています。
また、Makefile内でGO_BINを定義し、指定したディレクトリにバイナリファイルが設置されるようにしています。

SecretsをSecret Managerに登録する

こちらも、BerglasのREADMEに手順が記載されています。Dr.’s PrimeではGrant忘れなどを考慮して、MakefileでTarget定義をして登録作業を手元からできるようにしています。

set-secrets: ## Set secrets on sample-project (e.g. $make set-secrets KEY="test-key" VALUE="secret-value")
   @berglas create sm://$(PROJECT_NAME)/${KEY} "${VALUE}"
   @berglas grant sm://$(PROJECT_NAME)/${KEY} --member serviceAccount:$(AE_SERVICE_ACCOUNT)

Berglasを使ってアプリケーションからSecretsを参照する

環境変数の値を置き換える

まずは、既存の環境変数が定義されているapp.yamlをBerglasで利用できるように置き換えを行います。 Berglasは独自のsyntaxを定義しているので、先んじてこちらを確認してから置き換えすることをおすすめします。

# Before
env_variables:
  SUPER_SECRET_KEY: "<SUPER_SECRET_VALUE>"

# After
env_variables:
  SUPER_SECRET_KEY: "sm://sample-project/super-secret-key"

アプリケーション起動時にBerglasを呼び出して、自動的にSecretsを取得する

Dr.’s Primeは、Google App Engine (Go)で動いていることもあり、autoパッケージを各Serviceのmain.goにてInitialize importするだけで対応できました。本当にこれだけです。

import (
    ...
    _ "github.com/GoogleCloudPlatform/berglas/pkg/auto"
    ...
)

テスト時の不要なエラーを制御する

autoパッケージを利用している場合、テストを走らせたときにBerglasのClientが初期化できずにエラーが返却され、最終的にpanicが発生します。
これを解決するためにBERGLAS_CONTINUE_ON_ERRORという環境変数の値をtrueで渡すと抑制することができます。厳密にはstrconv.ParseBoolで取得されているので1とかtとかでも大丈夫ですが、見て意味がわかるようにtrueと記述しています。この情報は、autoパッケージのGoDocに記述されています。

Dr.’s Primeでは、GitHub Actionsを利用してCIを行っているので、testタスクの環境変数として定義しています。

env:
  BERGLAS_CONTINUE_ON_ERROR: "true"

まとめ

この記事では、Berglasを利用して安全にSecretを配布する事例を紹介しました。この作業によって、よりセキュアに行える為の土台が整いました。

Berglasは移行コストも少なくWrapperも便利ですがautoパッケージを利用している場合は、起動時にSecretsを環境変数に登録してしまいます。よりセキュアにするためには、BerglasのClientを利用する方法や、Secret Managerから直接取得するResolverを実装するなどの仕組みが必要です。(Secret Managerの公式ドキュメントにも書かれている方法です。)

とはいえ、Twelve-Factor Appを参照して実装しているWebアプリケーションも多いと思います。Berglasは、よりモダンなアプリケーションを目指すためのアプローチとしては始めやすいと思いますので、この記事がその手助けになれば幸いです。

書籍発売のお知らせ

f:id:drsprime:20211214224126p:plain:w300

2022年1月7日に技術評論社より「エキスパートたちのGo言語 一流のコードから応用力を学ぶ」が出版されます。
私だけではなくドクターズプライム Advent Calendar 2021の4日目を担当した生沼も執筆メンバーとして参加しています。総ページ数が400pあり読み応えも十分ですので、ぜひ一読して頂けると幸いです!

それでは、よいお年を!

一緒に働く仲間を募集しています

ドクターズプライムでは「救急車のたらい回しをゼロにする」というビジョンの実現に向けて、病院向けのSaaSプロダクトおよび、医師/病院間の最適なマッチングを提供するマッチングプラットフォームを展開しており、一緒に働く仲間を募集しています。

まずはカジュアルにお話ししてみませんか?

meety.net

speakerdeck.com