0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS】AWS PrivateLink におけるTLS設計の要点

0
Posted at

はじめに

AWS PrivateLink を利用してサービスを他 VPC や他アカウントへ公開する場合、以下のような構成を採用するケースがよくあります。

Consumer VPC
    ↓
Interface Endpoint
    ↓
Endpoint Service
    ↓
NLB
    ↓
ALB
    ↓
ECS

こういうときのTLSどうすんの?をまとめた記事です。

結論

  • TLS終端はNLBかALB
  • Private DNSで名前解決
Consumer VPC
┌─────────────────────────┐
│ https://api.example.com │
│     │ HTTPS             │
│     ▼                   │
│ Interface Endpoint      │
└─────┬───────────────────┘
      │ AWS PrivateLink
      ▼
Provider VPC
┌─────────────────────────┐
│ Endpoint Service        │
│ (Private DNS Name)      │
│     │                   │
│     ▼                   │
│ NLB (TLS Termination)   │
│     │ HTTP              │
│     ▼                   │
│ ALB                     │
│     │ HTTP              │
│     ▼                   │
│ ECS                     │
└─────────────────────────┘

1. TLS終端はNLBかALB

ECS終端にしない理由は、

  • 運用コストが小さいから
  • ALB~ECSは、AWS管理のVPC内で完結していてリスクが低く、わざわざ暗号化する必要がないから

ゼロトラスト要件のようにセキュリティ要件が厳しい場合は例外

cdk(typescript)での例

(NLB終端)

ACM証明書
import * as acm from "aws-cdk-lib/aws-certificatemanager";

const certificate = new acm.Certificate(this, "Certificate", {
  domainName: "api.example.com",
  validation: acm.CertificateValidation.fromDns(),
});
ALB
import * as elbv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";

const alb = new elbv2.ApplicationLoadBalancer(this, "Alb", {
  vpc,
  internetFacing: false,
});

// ALBのHTTP Listener
const albListener = alb.addListener("HttpListener", {
  port: 80,
});
NLB
import * as targets from "aws-cdk-lib/aws-elasticloadbalancingv2-targets";

const nlb = new elbv2.NetworkLoadBalancer(this, "Nlb", {
  vpc,
  internetFacing: false,
});

// ALBをNLBのターゲットとして登録
const targetGroup = new elbv2.NetworkTargetGroup(this, "AlbTargetGroup", {
  vpc,
  port: 80,
  protocol: elbv2.Protocol.TCP,
  targets: [
    new targets.AlbTarget(alb, 80),
  ],
});

// NLBのTLS Listener
nlb.addListener("TlsListener", {
  port: 443,
  protocol: elbv2.Protocol.TLS,
  certificates: [certificate],
  defaultTargetGroups: [targetGroup],
});

NLB→ALB のターゲットグループはTCPなのに、HTTP Listenerで受けるというのがややこしいところ


NLBとALBのどちらをTLS終端にするかは好みの問題っぽいです。WAFの手前で平文なのが気に入らないならALB終端という程度。
ただし、ALB終端の場合 NLB→ALB はTCPなのが注意点。

2. Private DNSで名前解決

ConsumerがVPCインターフェースエンドポイントを作成すると、AWSはvpce-xxxxxxxx.vpce.amazonaws.comのようなエンドポイントのDNS名を払い出します。
Consumer側の実際の接続先は、このDNS名です。

しかし、TLSの原則として

利用者がアクセスするFQDN
= TLS証明書のFQDN

である必要があります。なぜなら、接続先のDNS名がSNIに送信され、NLBやALBはこのSNIを見て証明書を返すからです。

そのためConsumerは、

api.example.com (TLS証明書のFQDNとする)
↓
vpce-xxxxxxxx.vpce.amazonaws.com

となるよう DNS を設定する必要があります。複数のConsumerがいるならそれぞれで設定しないといけないので面倒。

そこで登場するのがPrivate DNS Nameです。

  1. ProviderでVPCエンドポイントサービスに、api.example.comでPrivate DNS Nameを設定
  2. ConsumerはVPCエンドポイントのPrivate DNS Enabledを有効にするだけ
  3. api.example.comInterface Endpointが自動的に解決される

つまり、

利用者がアクセスするFQDN
= Private DNS Name
= TLS証明書のFQDN

が実現できる。

cdk(typescript)での例

Provider側

Endpoint Service
import * as ec2 from "aws-cdk-lib/aws-ec2";

const endpointService = new ec2.CfnVPCEndpointService(this, "EndpointServiceDns", {
  networkLoadBalancerArns: [nlb.loadBalancerArn],
  privateDnsName: "api.example.com",
  acceptanceRequired: true,
});

Consumer側

VPCEndpoint
const endpoint = new ec2.InterfaceVpcEndpoint(this, "Endpoint", {
  vpc,
  service: new ec2.InterfaceVpcEndpointService(
    "{EndpointServiceのvpcEndpointService名}",
    443
  ),
  privateDnsEnabled: true, // 承認前はtrueだとデプロイに失敗する
});

エンドポイントサービス側でまだ承認されていないエンドポイントは、Private DNS Enabledを有効にしてデプロイできない。したがって、最初は無効にしてデプロイして承認後に有効化する。

まとめ

AWS PrivateLink + NLB + ALB + ECS 構成では

  • TLS終端はNLBかALB
  • Private DNSで名前解決

が、シンプル・運用容易・コスト効率のバランスが最も良い構成です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?