[Terraform CLI]MFA認証を使ったAssumeRole。AWSVaultで解決

2021.01.14

はじめに

最近触り始めたTerraform CLI。Terraformコマンドを実行する権限は、AWS CLIと同じく.aws/credentials.aws/configを利用することができますが、MFA認証を使ったAssumeRoleを使う場合は、ひと手間が必要です。

MFA認証はエラーとなる

IAMを利用している方は、ユーザーおよびパスワードだけじゃなくMFAを必須とするポリシーで運用されている方が多いと思います。また、環境分離でAWSアカウント間はスイッチロールする運用されている場合、aws:MultiFactorAuthPresentをtrueとするように設定している方も多いかと思います。Terraform CLIでも同じくMFAを必須とするよう、credentials、configにmfa_serialが指定されたprofileを指定して実行すると以下のエラーが発生します。

Error: error configuring Terraform AWS Provider: Error creating AWS session: AssumeRoleTokenProviderNotSetError: assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.

AWS CLIなら対話型で6桁のMFAコードを入力して認証情報(AccessKeyId、SecretAccessKey、SessionToken)を取得して実行しますが、Terraform CLIではMFAコードの入力が求められません。どうやら対話型認証はサポートされていないようです。「じゃあMFAを無効化するか」と簡単にセキュリティポリシーを曲げるわけにもいかないのでMFAが必須とする環境で実行できる方法を調べてみました。その一つがAWSVaultです。

AWSVaultとは

AWSVaultは、作業端末のキーストアで認証情報を生成、保存して利用するツールです。先程のIssueでもワークアラウンドとしてもコメントされています。以下、概要です。

AWSValut

AWS Vault is a tool to securely store and access AWS credentials in a development environment.

AWS Vault stores IAM credentials in your operating system's secure keystore and then generates temporary credentials from those to expose to your shell and applications. It's designed to be complementary to the AWS CLI tools, and is aware of your profiles and configuration in ~/.aws/config.

様々なOSで利用できます。筆者の作業端末はMacOS(Catalina)なのでHomeBrewからインストールできます。また、キーストアとしてキーチェーンが利用できます。

やってみた

READMEに従ってaws-vaultをインストールします。以下のコマンドでバージョン情報が出力されればOKです。

% aws-vault --version

AWSVaultで認識されている資格情報を確認できます。

% aws-vault list
Profile                      Credentials              Sessions                    
=======                      ===========              ========
default                      -                        -                           
role1                        -                        -                
role2                        -                        -                
role3                        -                        -                

筆者の環境では、defaultで指定したIAMユーザのAccessKeyId、SecretAccessKeyを.aws/credentialsに格納し、role1~3へAssumeRoleして操作しています。aws-vaultで認証情報を生成できるようにdefaultのAccessKeyId、SecretAccessKeyをキーチェーンに登録するaws-vaultコマンドを実行します。

% aws-vault add default
Enter Access Key Id: ASDFGHJKLASDFGHJKL
Enter Secret Key:

なお、コマンド実行時に以下のポップアップが出てきます。AWSVaultで生成するキーチェーンにアクセスする為のパスワードを任意で設定します。

再度、AWSVaultが認識している資格情報を確認するとdefaultのcredentialsにdefaultと表示されます。

% aws-vault list
Profile                      Credentials              Sessions                    
=======                      ===========              ========                    
default                      default                  -                           
role1                        -                        -                
role2                        -                        -                
role3                        -                        -                

これで準備OKです。それでは、Terraform CLIを実行してみます。main.tfの中身は、providerおよびresourceブロックでEC2インスタンスを作成するテンプレートです。

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

resource "aws_instance" "sample" {
    ami = "ami-012345678910abc"
    instance_type = "t3.nano"
    subnet_id = "subnet-012345678910abc"
    vpc_security_group_ids = [ "sg-012345678910abc" ]
    tags = {
      "Name" = "temp-20210114"
    }
}

role1のAWSアカウント上でインスタンスをデプロイしていきます。コマンドの実行方法は、aws-vaultコマンドを先頭に実行します。まずは初期化していきます。

% aws-vault exec role1 -- terraform init

MFAコードの入力とaws-vaultキーチェーンへアクセスする為のパスワードが求められるのでそれぞれ入力します。

Enter token for arn:aws:iam::123456789101:mfa/user1:

以下は、aws-vault add default実行時に設定したパスワードを入力し、「常に許可」を選択すればパスワード入力が求められなくなります。

下は、MacOSにログインする際のパスワードを入力します。

初期化のコマンドが実行できたらapplyします。 % aws-vault exec role1 -- terraform apply 〜省略〜 Apply complete! Resources: 1 added, 0 changed, 0 destroyed. 無事にMFA認証されたAssumeRoleでAWSリソースをデプロイできました。AWSVaultを使うと.aws/credentials.aws/configに手を加えること無くMFA認証を利用したTerraform CLIが実行できます。

キーチェーンアクセスで度々パスワード入力が求められる

MFAが認証が利用できて安心していたのですが、キーチェーンアクセスのパスワードの入力を求めるポップアップが頻繁に表示されるようになった。

結構な頻度で表示されるので原因を調査すると、対象のキーチェーン(今回だとaws-vault)に5分間アクセスがなかった場合にロックする仕様となっているようです。

安心してください。対策あります。

Issueにあがっていました。

まず、キーチェーンにaws-vaultを追加します。

~/Library/Keychains/aws-vault.keychain-dbを指定して追加すると、キーチェーンにaws-vaultが追加されます。右クリックして「キーチェーン"aws-vault"の設定を変更」をクリックします。

設定画面でロック時間を指定できます。AssumeRoleのセッション時間と同等または、チェックを外して無効にすることで調整できます。

おわりに

AWSVaultを使ったMFA認証方法のご紹介でした。AWSVaultおよび.aws/credentialsでAccessKeyId、SecretAccessKeyの管理が重複するのでTerraformしか使わないって環境ならAWSVaultだけで管理するほうが良いかと思います。

余談

筆者は、terraformコマンドが長いのでalias tf='terraform'を仕込んでいたのですが、aws-vault execコマンドの引数でterraformを指定すると、エラーになります。($PATHを参照する為)

aws-vault: error: exec: Couldn't find the executable 'tf': exec: "tf": executable file not found in $PATH

なのでaliasでなくシンボリックリンクであればエラーになりません。

ln -s /usr/local/bin/terraform /usr/local/bin/tf