saml2awsを使ったセキュアなTerraform管理

saml2awsを使ったセキュアなTerraform管理

こんにちは kotamatです。

本日発売の WEB+DB PRESS Vol.111に 【第2回】コードの書き方の統一 ……PHP_CodeSnifferによる規約への準拠,PHPStanによる静的解析……というタイトルで寄稿させていただいております。

gihyo.jp

PHPをチームで開発されている方にはぜひ読んでいただければと思っております! が、今日は最近触っているインフラに関して、工夫したところを紹介させていただきます。

Terraform の provider管理

インフラ構築をよりセキュアにするために、SARDINE全体的にインフラを再構築しました。 今までTerraformでインフラを構築してきましたが、providerを下記のようにAWS のIAM keyを用いて実装してきておりました。

provider.tf

# Configure the AWS Provider
provider "aws" {
  region     = "ap-northeast-1"
  access_key = "my-access-key"
  secret_key = "my-secret-key"
}

GitHubでインフラ構成を管理しているのですが、もちろんこれだとコードベースにkeyがコミットされてしまい、必要以上のメンバーに共有されてしまいますので、Terraformのvariableを使い、コミットしない形で運用しておりました。

provider.tf

provider "aws" {
  region     = "ap-northeast-1"
  access_key = var.access_key
  secret_key = var.secret_key
}

variable.tf

variable "access_key" {}
variable "secret_key" {}

こうすることによって、対象のユーザごとにIAMユーザを作成し、適切な権限のみを与えることによってユーザを管理する事ができました。不必要になったタイミングで当該ユーザを消したりaccess keyを失効することによってログイン出来ないようにできますが、このような運用は頻度が多くなると大変ですし、なんといってもアカウント発行、失効の属人性も上がり、更にはPC側にkeyが残ってしまうことによって端末紛失などに耐えられない構成となっていることが課題でした。

この問題を解決するために、applyユーザだけはステップサーバーなど別のインスタンスだけで実行できるようにし、自動的にapplyが走るという環境を整備されているところもありますが、いくらplanやvalidateをしているとはいえ、apply時に実行時エラーが出ることもあるため、何かが発生したときの対応が難しく、やはりある程度は手元で実行できるようにしておきたいです。

AWS SSO as SP

そこで、今回導入したのが、SAMLベースでの認証形式を用いた構成です。 AWSにはSSOの仕組みがありますが、通常はIdPをAWSのIAMとした上でのSSOの構成を行うと思います。 ただ、逆にAWSのIAMにIdPを登録することによって、SAML形式かOpenID Connect形式によるAWSへの認証を行うことができます。

詳細の設定方法はAWSのブログが詳細を紹介されておりますので、こちらをご覧ください。

aws.amazon.com

こちら見てもらえるとわかりますが、ユーザごとにSession時間を設定する項目があり、デフォルトは1時間ですが、Terraformの設定中は1時間以上の作業時間を設ける事があると思いますので、こちらの設定項目を随時変更する事によって作業時間中にセッションが切れることがなくなります。

SSOをどうやってつかうのか

通常SSOはコンソール上で使用しているため、webの画面で使用するものかと思います。 しかしsaml2awsというものを使うことによって、任意のプロバイダーでのSSOログインをCLI上のみで行い、かつそのユーザをセッション付きで ~/.aws/credentials に保存することができ、そのユーザを用いてTerraformのproviderを設定することができます。

内部構造としては、go queryを用いてWebページにアクセスし、認証しているようです。

具体的な使用方法

saml2awsの設定

まずはsaml2awsに使用するIdPを設定します。

~/.saml2aws

[gsuite]
app_id               =
url                  = <GSuite側のログインURL>
username             = <GSuiteアカウント>
provider             = GoogleApps
mfa                  = Auto
skip_verify          = false
timeout              = 0
aws_urn              = urn:amazon:webservices
aws_session_duration = 3600 # 秒。必要であれば伸ばす
aws_profile          = saml # 使用したいprofile名
resource_id          =
subdomain            =
role_arn             =

設定後下記のコマンドでログインします。

saml2aws login -a gsuite

もしユーザ名、パスワード入力を省略したい場合は下記のようにします(端末にパスワードが残ってしまうので、あまりおすすめはしません)

saml2aws login -a gsuite --username=username --password='password'

Using IDP Account gsuite to access GoogleApps <GSuite側のログインURL>
To use saved password just hit enter.
? Username username
? Password

Authenticating as username ...
Open the Google App, and tap 'Yes' on the prompt to sign in

MFAを有効にしている場合、こちらが出たら端末側でYesをおします。

? Please choose the role  [Use arrows to move, type to filter]
  Account: XXX / role1 
  Account: XXX / role2 
  Account: XXX / role3 
❯ Account: XXX / role4 
  Account: XXX / role5 
  Account: XXX / role6 
  Account: XXX / role7 

そうすると、当該ユーザに紐付いているroleの一覧が表示されるので、適切なユーザを選択するだけです。

そうすることによって、 ~/.aws/credentialsに saml2awsに設定したprofile名でcredentialが保存されます。

Terraformのproviderを修正

最後にproviderの設定を修正します。

provider "aws" {
  region     = "ap-northeast-1"
-  access_key = var.access_key
-  secret_key = var.secret_key
+  profile = "saml" # saml2awsで設定したprofile名
}

Terraformの設定ファイル上では、saml2awsの内容ではなく、あくまでAWSのprofile名という抽象レイヤーで記述するので、他ツールに移行も簡単なのが便利ですね。

ログイン情報の除去

いくらSTSで期限付きのユーザを発行したとはいえ、ログイン情報をアカウントに保持させ続けるのは不安です。 そういった場合でも、GSuiteなどのIdP側のAttributeから、当該ロールを除外してあげるだけで、そのユーザからは二度とログインができなくなり、実質Terraformの実行権限がなくなります。

まとめ

AWS STSを用いたログイン方法を紹介させていただきました。 Terraformのベストプラクティスは結構各々実装しており散在している印象です。 この記事がなにかの手助けになれば幸いです。

最後に

弊社ではエンジニアを募集しております!

ぜひご応募ください!

www.wantedly.com