ノート PC が Client VPN エンドポイントに接続しても、terraform apply はルートリソースで失敗し続けます。構成では通常、関連付けたサブネットより宛先 CIDR のほうが多く、ルートブロックはインデックスでターゲットを選びます。これは二つのコレクションが並行していることを前提にしています。実際はそうではなく、失敗はレビュー時ではなく適用時に表面化します。

失敗するオブジェクトを名指しする

関与するリソースは三つあり、それぞれ別の問いに答えます。関連付けはエンドポイントのネットワークインターフェースをサブネットに配置します。ルートはどの宛先プレフィックスをターゲットサブネットに届けるかを示します。認可ルールはどのユーザーがどのプレフィックスに到達できるかを示します。一度も関連付けていないサブネットを指すルートは、ターゲットがこのエンドポイントに属している必要があるため、両方のオブジェクトが存在していても失敗します。

まず関連付けを一覧します: aws ec2 describe-client-vpn-target-networks --client-vpn-endpoint-id cvpn-endpoint-0123456789abcdef0。

VPC のローカルルートを忘れない

最初の関連付けは VPC 全体にローカルルートを追加するため、その VPC 内のすべてのサブネットはルートリソースなしで既に到達可能です。追加のルートは、ピア接続した VPC、Transit Gateway の接続、VPC が所有しないオンプレミスのプレフィックスに存在します。そのため、関連付けが三つあるエンドポイントが七つの宛先エントリを持つことは正当です。

ルートを追加する前に、VPC の外にある宛先を数えます。その数が CIDR 一覧より少ない場合、一覧はルートをまったく必要としないサブネットを記述しています。

インデックスをマップに置き換える

インデックスをモジュロ演算子で包むとエラーは静まり、モデリングの誤りは残ります。選んだターゲット経由で到達できない宛先は、プランがどれほどきれいに適用されてもトラフィックを運びません。代わりに関係を保存し、何かを作成する前に Terraform に検証させます。以下のブロックは例示であり、プロバイダーのエンドポイントルート引数を使用します。

variable "client_vpn_destinations" {
  description = "Destination CIDR mapped to an associated subnet key"
  type        = map(string)
}

resource "aws_ec2_client_vpn_route" "this" {
  for_each               = var.client_vpn_destinations
  client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.this.id
  destination_cidr_block = each.key
  target_vpc_subnet_id   = aws_subnet.private[each.value].id

  lifecycle {
    precondition {
      condition     = contains(keys(aws_subnet.private), each.value)
      error_message = "Route target must be a subnet key in the associated map."
    }
  }
}

マップが関連付け一覧の隣にあると、宛先を追加するときにどのサブネットが運ぶかを決めざるを得ません。それがインデックスが隠していた会話です。

別の失敗はインデックスエラーではなく無意味な値を生みます。高レベルのインターフェースが期待される場所に低レベルの構文を渡すと、API が読むフィールドが埋まらず、結果の CIDR は使えません。Terraform は、オブジェクトが期待される場所に文字列が来たときも同じ形を示します。引数の型についてはプロバイダーのスキーマを確認します。

クライアントから証明する

適用前に terraform validate と実状態に対するプランを実行します。その後、成功した apply を信じるのではなく、エンドポイントのターゲットネットワーク一覧をマップと比較します。

受け入れテストは、意図した各プレフィックスに到達する接続済みクライアントです。

認可ルールは多くの構成が早く止まる場所です。これは宛先 CIDR とグループに限定され、対応する認可のないルートはプレフィックスに到達できない接続済みクライアントを生みます。ルートを作成してルールを忘れる apply は完全に見えるため、すべてのプレフィックスで両方のオブジェクトを確認します。グループ内のユーザーとグループ外のユーザーで試します。

一つのプレフィックスが失敗したら、そのルートエントリを認可ルールと比較します。認可の欠落とルートの欠落はクライアントログで似て見え、別のリソースで修正されます。

関連記事