AppConfigのPrivateLinkを活用して、セキュアなアプリケーション設定を実現する方法

急遽帰省することになり、AWS Summit Japan 2024には関東に戻れるといいなと思っております。 AWS AppConfigがAWS PrivateLinkをサポートし始めたのが2023年12月のことで、まだ記憶に新しい出来事です。

aws.amazon.com

本ブログ投稿では、Amazon ECS on Fargateを例として、AWS AppConfigのPrivateLinkのサポートを活用した具体的な設定方法と注意点をご紹介します。

読者の前提条件

  • ✅ AWS AppConfig、VPCエンドポイント、Amazon ECSを概要レベルで理解している必要があります。

AWS AppConfigのAWS PrivateLinkサポートで何が変わるのか

これまでは、プライベートサブネットからAWS AppConfigを利用するためには、NATゲートウェイが必要でした。

NATゲートウェイを利用したAWS構成図

AppConfigがPrivateLinkに対応したことで、AppConfigへのアクセスをVPC Interface Endpointを経由して行えるようになり、NATゲートウェイが不要になりました。

VPCエンドポイントを利用したAWS校正図

ECSを活用した閉域環境でのAppConfigの活用例

ここからは、Amazon ECSの例を用いて、AppConfigのPrivateLinkを利用する方法をご紹介します。

AWS構成図

この活用例では下図のような、よくある閉域環境でのAmazon ECSによるAPIサーバーのAWS構成図になっています。ですので、Amazon ECSに必要なVPC Interface Endpointも含まれています。ecr.api , ecr.dkr , logs のVPC Interface Endpointが該当します。

ECSを活用した閉域環境でのAppConfigの活用例 - AWS構成図

この活用例で利用したソースコードは、以下のGitHubリポジトリにありますので、ご参照いただければと思います。

github.com

1. IaCによるAmazon ECSとAWS AppConfigのセットアップ

この活用例では、インフラストラクチャのプロビジョニングにTerraform、コンテナのデプロイにecspressoというツールを用いて、インフラとアプリケーションの管理を分離しています。AWS AppConfigについては以下のコードの内容でPrivateLinkを利用するためのセットアップを行っています。

# VPC Endpoint
resource "aws_vpc_endpoint" "vpce_appconfig" {
  vpc_id            = var.vpc_id
  service_name      = "com.amazonaws.ap-northeast-1.appconfig"
  vpc_endpoint_type = "Interface"

  subnet_ids = [
    var.subnet_id_private_c
  ]

  security_group_ids = [
    aws_security_group.yassan-fa-ac-vpce-sg.id,
  ]

  private_dns_enabled = true
}

resource "aws_vpc_endpoint" "vpce_appconfigdata" {
  vpc_id            = var.vpc_id
  service_name      = "com.amazonaws.ap-northeast-1.appconfigdata"
  vpc_endpoint_type = "Interface"

  subnet_ids = [
    var.subnet_id_private_c
  ]

  security_group_ids = [
    aws_security_group.yassan-fa-ac-vpce-sg.id,
  ]

  private_dns_enabled = true
}

AWS AppConfigの機能フラグについては以下のコードでセットアップを行っています。

# AppConfig
resource "aws_appconfig_application" "yassan-ac-app" {
  name = "yassan-ac-app"
}

resource "aws_appconfig_configuration_profile" "yassan-ac-c-profile" {
  application_id = aws_appconfig_application.yassan-ac-app.id
  location_uri   = "hosted"
  name           = "yassan-ac-cprofile"
  type           = "AWS.AppConfig.FeatureFlags"
}

resource "aws_appconfig_hosted_configuration_version" "yassan-ac-hcv" {
  application_id           = aws_appconfig_application.yassan-ac-app.id
  configuration_profile_id = aws_appconfig_configuration_profile.yassan-ac-c-profile.configuration_profile_id
  content = jsonencode({
    flags : {
      featureA : {
        name : "featureA"
      }
    },
    values : {
      featureA : {
        enabled : "false"
      }
    },
    version : "1"
  })
  content_type = "application/json"
}

resource "aws_appconfig_environment" "yassan-ac-env-dev" {
  application_id = aws_appconfig_application.yassan-ac-app.id
  name           = "yassan-ac-env-dev"
}

resource "aws_appconfig_deployment_strategy" "yassan-ac-deploy-stg" {
  deployment_duration_in_minutes = 0
  growth_factor                  = 100
  final_bake_time_in_minutes     = 0
  name                           = "yassan-ac-deploy-stg"
  replicate_to                   = "NONE"
}

resource "aws_appconfig_deployment" "yassan-ac-deployment" {
  application_id           = aws_appconfig_application.yassan-ac-app.id
  configuration_profile_id = aws_appconfig_configuration_profile.yassan-ac-c-profile.configuration_profile_id
  configuration_version    = aws_appconfig_hosted_configuration_version.yassan-ac-hcv.version_number
  deployment_strategy_id   = aws_appconfig_deployment_strategy.yassan-ac-deploy-stg.id
  environment_id           = aws_appconfig_environment.yassan-ac-env-dev.environment_id
}

2. AppConfigのVPCエンドポイントのプロビジョニング結果を確認する

上記のIaCをプロビジョニングしてAppConfigのVPCエンドポイントを追加します。AppConfigは2種類のエンドポイントがあり、「com.amazonaws.region.appconfig」と「com.amazonaws.region.appconfigdata」の両方のVPC Interface Endpointを設定してあげる必要があります。

VPC Interface Endpointの設定は、他のサービスと同様に、HTTPS(ポート443)に対するインバウンドを許可するセキュリティグループと、プライベートサブネットの指定が必要です。

VPC Interface Endpointの設定例

3. APIにアクセスしてAppConfigの機能フラグの状態を確認する

Web APIのエンドポイントをブラウザから呼び出して、APIがAppConfigから機能フラグを取得する動作を確認します。以下の画像のように、レスポンスにはconfig情報を含むJSONが返され、AppConfigから設定内容を適切に取得できていることが確認できます。

Web APIのレスポンス内容

4. AppConfigの機能フラグを切り替えて動作確認する

次に、AppConfigの設定を更新しても正しく動作するか確認します。ここでは機能フラグを切り替えます。以下の画像のように、フラグをオンに変更してデプロイします。

機能フラグの設定変更

デプロイ後にもう一度Web APIのエンドポイントをブラウザから呼び出すと、config情報のJSONの値が変更されていることがわかります。機能フラグの切り替えが適切に反映されていました。

機能フラグ切り替え後のWeb APIレスポンス確認

AWS AppConfigのPrivateLinkをプロビジョニングしない場合はどうなるのか

AWS AppConfigのPrivateLinkをプロビジョニングしない場合はどうなるのか確認してみました。以下のCloudWatchLogsの内容から、タイムアウトエラーが発生しており、ECSタスクのAppConfigサイドカーコンテナでエラーが発生していることを確認できました。

タイムアウトエラーのログ情報

注意点:AppConfigエージェントのコンテナイメージの取得について

AppConfigエージェントのコンテナイメージはECR Publicで公開されています。閉域環境でAWS PrivateLinkを利用する場合はECR Publicに接続できなくなります。その結果としてコンテナイメージを取得できず、ECSサービスが起動できない問題が発生します。この問題を解決するための有効な方法として、Pull through cacheの設定を行うことができます。

Pull through cacheを利用したAppConfigエージェントのコンテナイメージの取得方法

Pull through cacheを利用したAppConfigエージェントのコンテナイメージの取得方法を解説します。 まず、以下の画像のように、Pull through cacheを設定します。

Pull through cacheの設定

次にAWS CLIを利用してECRにログインします。

# ログインコマンド例
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-public

ECR Publicにあるコンテナイメージを取得するには、ecr-publicのnamespaceを指定する必要があります。

# ECR Publicからコンテナイメージpullの例
$ docker image pull xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-public/aws-appconfig/aws-appconfig-agent:2.x

すると、自動的にプライベートリポジトリにPull through cacheとして保存されます。

保存されたPull through cache

あとは、ECSのタスク定義に、キャッシュされたコンテナイメージのURIを指定するだけでOKです。

ECSタスク定義にPull through cacheで取得したコンテナイメージを指定

おわりに

AppConfigのPrivateLinkを活用して、セキュアなアプリケーション設定を実現する方法をご紹介しました。今回はECSの事例でしたが、機会があればVPC Lambdaにおけるプライベートサブネットでの利用例も紹介できればと考えています。AppConfigは漸進的なアプリケーション構築に必須であり、積極的に活用していきたいと考えております。参考になれば幸いです。