データレイクのおじさん

Noteもやってます:https://note.com/yukinkoyuki

AWSのプライベートサブネットに配置すると言うこと

プライベートサブネットで運用するとは?

面倒くささと引き換えにセキュリティとして安全であるということ。

要件が許すのであれば、全部パブリックが嬉しいいがそうもいかない。仮に要件がそうなっていなかったとしてもデータの安全性を考慮するのであれば、インターネット経由で出ない方がお金的にも、運用的にも(NAT)、セキュリティ的にも嬉しい。

データエンジニア が利用するサービス

EMR ワークフローエンジン構築 athena など分析系のサービスが多いのと、他のサービスと同様に、S3が中心になることが多い。

プライベートサブネット上のインスタンスからS3にアクセスするには?

原則同一リージョンであれば、VPC gatewayをを経由して、プライベートな通信が可能だし、そうするべき。

しかし、別リージョンににアクセスする際は、インターネットとの通信が必要になるので、NATなどの外に出るためのコンポーネントが必要になってくる。

Natなど外に出る経路がないプライベートサブネット内で、カリフォルニアのリージョンで試すとこんな感じ。

aws s3 ls s3://tokyo/ --profile eval --region us-west-1
アクセスできない

aws s3 ls s3:// us-west-1/ --profile eval --region us-west-1
アクセス可能

当然だけど、必要のない限りリージョン間の転送料金がかかるので、通信は同一のリージョン内に納めておくのがベター。

EMR

EMRは大きく分けて、EMR serviceと言う、リージョンに存在するサービスと、クラスター(EMR serviceによって立ち上げられる)コンポーネントでできている。例えばプライベートサブネット内のインスタンスにおいてboto3 経由で特定のクラスター(同一VPCでも別VPCでもOK、別リージョンはNG)にadd stepや、describe-clustersを投げた時。

通常は、インターネット経由でこのEMR serviceにコマンドが到達し、Emr serviceからインターネット経由(プライベートなEMRであればENI(プライベートリンク)経由)とアクセスを代行してくれる。

図で表すとこんな感じ

f:id:yk_st:20200628200509j:plain
public
f:id:yk_st:20200628200506j:plain
private

一枚目に記載忘れましたが、EMR-serveiceから各クラスターへは2枚目(private)と同じです。

このprivate subnetから各AWSのサービスにアクセスするための経路をprivate linkと呼んでいるそう。 これを実現するには、private subnetに対象サービスへのネットワークインターフェースを追加する必要があります。

terraformのソースは以下のような感じ。

resource "aws_vpc_endpoint" "emr_service_endpoint_attach" {
  service_name      = "com.amazonaws.${data.aws_region.current.name}.elasticmapreduce"
  vpc_endpoint_type = "Interface"
  vpc_id            = "${aws_vpc.vpc.id}"
  subnet_ids        = "${aws_subnet.vpc_subnet_private.*.id}"
  security_group_ids = [
    "${aws_security_group.workflow_security_emr_service.id}",
  ]
  private_dns_enabled = true
  tags = {
    department = var.department,
    Name       = "${var.department}_workflow_emr_service"
  }
}

ちなみに、同時に使うことが多いであろう、glueも同じような仕組みになっています。

Fargate

コンテナになってくると、さらに複雑かつ必要性が増してきます。

コンテナの起動には、以下のエンドポイントが必要です。

  • logs(cloud watch)
  • s3
  • dkr(コンテナのイメージをecrからpullしてくる)

また、コンテナのイメージをインターネット経由でALBやNATを通して、ダウンロードしてきたりすると(データ基盤のコンテナイメージはデカくなりがちです、10Gとか普通(結局そっちの方が効率いいから詰め込んじゃえ的な)、値段が一気に跳ね上がり死亡します。 そのため、コンテナのpullはお金的にも、セキュリティ的にもプライベート経由での実施が好ましいというかマストです。

当然ながら、このコンテナの中からEMR serviceやGlue API gatewayなどなどのサービスにアクセスしようとした時も、privatelink の設定が必要なります。

バランス

個人的にですが、基本的にはprivate。特にマルチテナントで様々な人がいじるような環境の場合はprivateにするようにしています。 インターネットにアクセスと言う強力なツールを様々な人に与えると、何をされうるか判ったものではありません(たとえ社内の人だとしても)。また、外部からの攻撃は防ぎやすいですが、内部からの攻撃(いろいろな意味で)はなかなか防ぎきれないものです。

逆に、各テナントごとに好きにして欲しい場合などはVPC単位で分けて、利便性を優先してパブリックなサブネットに配置していることが多いです(当然IPの制限などは行います)。

この時にこれと言う、正解はないのですが私はこんな感じで考えて選択をしています。

理解して選択しているのと、知らずして選択しているのでは訳が違うので何がなんでもパブリックに置いて「よっしゃうごいた」というレベルから「運用可能な」レベルまで持っていけるように常に考えていきたいものです。