Terraformでstate lockを触ってみた。

はじめに

初めてTerraformを触る折に
「v0.9以上だとstate lockっていう機能があるから使ったほうが良いよ」
というアドバイスをもらいました。
(そもそも、stateってなんですか?から始まるわけですが・・・)

初めてTerraformを触った時に、公式ドキュメントだけでは???な状態だったので
痕跡として残しておきます。

結果として、まだ使いこなせてません。というか僕の使い方は果たしてあっているのだろうか
なので情報としては不足しているかもしれませんが、とりあえず備忘録的に残します。
またわかったらUpdateします。

そもそもState Lockとは

完全に理解しないで書いてますが
Terraformは「自分が知っているリソース(EC2やS3)しか関与しないよ」というポリシーで
どのリソースを自分が扱ったか、というのをtfstateというJSONファイルで管理しているようです。

このtfstateファイルは、一人でTerraformを動かす場合は問題無いのですが
複数人でTerraformをいじる必要が出てきた時に問題で、それは「backend」モジュールを使うことで回避してきたようですが
同じタイミングでterraformを実施した場合、その部分までは制御しきれてなかったようです。

で、v0.9以上?から、「Plan/Applyをしているタイミングではロックする」機能が実装されたようで。
せっかくなので導入してみました。

公式サイト:https://www.terraform.io/docs/state/locking.html

準備

手動で準備が必要なものは
・terraformを実行するユーザのCredential情報
→ めんどくさかったので test-terraformとかいうユーザを別途作成しました。
・S3 Bucketの作成
→ terraform-s3-state とかいう名前で作りましょう
・DynamoDBの作成
→ 名前はなんでも良いです。terraform-state-lock とかで作りましょう。
  プライマリキーを「LockID」としてください。それ以外では動きません。
作り終えたら、読み込み・書き込み容量ユニットは最低の1にしておいたほうが良いと思います。

※ S3とDynamoDBをterraformで管理はしないほうが良さげです。
どのみち、初回実行時に「そんなリソース無いんだけど!」ってTerraformが怒ります。

動くまで

今回はState Lockの話がメインなので作るリソースはなんでも良いです。
リージョンが関係無いRoute53を題材にします。

route53.tf
# 適当に1ゾーン作ります。

resource "aws_route53_zone" "test_zone" {
    name    =   "test.lockstate.com"
}
settings.tf
# ネーミングよくないですが、providerとbackendの設定します

provider "aws" {
    access_key = "ACCESS_KEY"
    private_key = "PRIVATE_KEY"
}

terraform {
    backend "s3" {
        bucket     = "terraform-s3-state"
        key        = "terraform.tfstate"
        region     = "s3とdynamoがいるregion"
        lock_table = "terraform-state-lock"
    }
}

これで、「該当のディレクトリに移動して」$ terraform plan してください。(怒られます。)

Backend reinitialization required. Please run "terraform init".
Reason: Initial configuration of the requested backend "s3"

The "backend" is the interface that Terraform uses to store state,
perform operations, etc. If this message is showing up, it means that the
Terraform configuration you're using is using a custom configuration for
the Terraform backend.

とりあえず terraform init しろよと言われるので言われるがままに。

$ terraform init

ただし、以下の通り、認証情報がねーんだけど!って怒られる。なんやねん。

Initializing the backend...

Error configuring the backend "s3": No valid credential sources found for AWS Provider.
  Please see https://terraform.io/docs/providers/aws/index.html for more information on
  providing credentials for the AWS Provider

Please update the configuration in your Terraform files to fix this error
then run this command again.

ここらへんちゃんとよくわかってないですが、この問題の対処として2つありました。
A. settings.tfのbackendにaccess_key/secret_keyの2つを渡してCredential情報を平文で書く。
-> 変数でいいじゃん!と思ったんですが、変数で渡すと、Terraformがよしなにやる「前に」
  Backendが立ち上がるために違う方法で渡してくれ、と怒られました。
以下のようなメッセージ

% terraform init 
Initializing the backend...
Error loading backend config: 1 error(s) occurred:

* terraform.backend: configuration cannot contain interpolations

The backend configuration is loaded by Terraform extremely early, before
the core of Terraform can be initialized. This is necessary because the backend
dictates the behavior of that core. The core is what handles interpolation
processing. Because of this, interpolations cannot be used in backend
configuration.

If you'd like to parameterize backend configuration, we recommend using
partial configuration with the "-backend-config" flag to "terraform init".

B. 環境変数にaccess_key/secret_keyの2つを食わせる
  → 今はこちらを採用中。

init or plan実行時に、状況に応じて「ローカルのStateをS3にコピーするか / S3からStateファイルをローカルにコピーするか」聞かれるかもしれません。
初回(もしくはテスト)であればYes、すでに何回か実行しているような状況ではnoでいいんじゃないでしょうか。

これで、terraform plan (or apply)を実行すると
DynamoDBのLockDBに対して誰が使用しているか、のロック情報が書き込まれ
終わったタイミングでリリースされます。

ターミナルやシェルを複数立ち上げ、同じぐらいのタイミングで
terraform plan( or apply )を実行すると、ロックが成功できた奴以外はエラーで落とされます。
ただし、ロックがリリースされる前の実行中などにCtrl-Cなどで強制終了させるとロックが残り続けるので注意。
$ terraform force-unlock ID情報
で強制ロック解除できます。

今僕が解決できてない問題点

公式ドキュメントを見る限り、「terraform remote コマンドは terraform initコマンドに置き換えたよ!」と言っています。
また、backendを使用する、backendを書き換えた、などのタイミングに起因して terraform init を求められます。

が、terraform initは、「実行されたディレクトリに対して .terraform/terraform.tfstate」を吐き出します。
そしてそれが無いと怒ります。
まだ試せてはいませんが、以下のようなtfの配置をしていたりした場合
root配下でinitを実行しても、tfファイルがありませんと怒られる状況で
tfファイルがあるディレクトリまで移動しないとinitができない状態です。

$ terraform init ./route53/tf
とするとroot直下にtfファイルがコピーされる状況です。
なので、リソースごとに区切る、とか環境ごとに区切る、とかはうまくできていません。
別の見方をすれば、環境ごとに一つのディレクトリでリソース類は全部その中で管理しろよ!
というHashiCorpからのお達しなのか・・・?
これは、新しく実装されたEnvironmentを試せ、ということなんでしょうか。。。

と思ったらBackendConfigなるものがあるらしいのでそれを試してみよう。

root
├── settings
│   └── tf
│   └── settings.tf
├── route53
│   └── tf
│   └── route53.tf
└── ec2
└── tf
└── ec2.tf

Terraformとの付き合い方がよくわからない

続きを読む

AWSで仮想MFAを紛失したので対応したメモ

この記事の目的

AWSの1年間無料が終わったので、さてAWSをサクッと解約しよう
と思った矢先思い出したのが、諸事情によりiPhoneを交換したこと。
GoogleAuthenticatorを起動するとそこには空白しか存在しなかった。

ので、MFAを解除してみた時の流れを

記憶が確かならば、勉強がてらに起動してたインスタンスが1個いた気がしたので
お金かかるのも嫌だし、AWSログイン時のフォーム()から問い合わせる。
(
Having problems with your authentication device? Click here とか書いてある)

電話番号を求められる

AWSに紐付いてた電話番号だよね?っていう確認すらしないまま投稿してますごめんなさい。
僕は普通に 080〜から始まる電話で、「日本」を選びました。

入力後
Thank you. Your request for help with your AWS MFA authentication device has been received.
って出てきた。

なんかメールでも来るんかいな?と思っていたら

シアトルからの電話

家には諸事情からネット回線が無く、Wi-Fiを求めてカフェで作業してましたが裏目に出て普通に電話がかかってきた。

あっち「AWSのモノです。どうも」
わたし「どうも。日本語のサポートをお願いしたいんだけど」
あっち「わかった。で、今回どうしてこのrequestをしてきたの?(!?)」

英語で電話してくるの分かってたから日本語のサポートをお願いしたはずが。。。

とりあえず、前の携帯をなくしてしまって新しくしたからGoogleAuthenticatorがオワコンなんや助けてクレメンス
(Because, I lost my cell phone with google authenticator, and couldn’t login to AWSとか言ったら通じた。)
とだけ簡単に言うと、おっけー、みたいな感じで色々英語で言われる。。。が早すぎてついていけない

メアドだけでログインできるようになるまで

その後に、Mail address…的な言葉を言われたので
AWSにログインするためのメールアドレスを伝えるとPerfect,との返事。

その後、メアドにメール送ったけど確認できた?読み上げて?的なことを言われたので
ワンタイムパスワードを読み上げる。

その後、電話口から「もうログイン出来ると思うけど、試してみて」って感じで言われ
ログインし直すとダッシュボードが見える。そして2ドルほど徴収されることが決定されていた。

終わりに

普段2FAでGoogleAuthenticatorとかをきちんと使わない人は
無くした時のための策をねっておこう。

続きを読む