Help us understand the problem. What is going on with this article?

EKSを経由してS3 Static Websiteにアクセスする

はじめに

静的サイトをサーバレスで公開したいときの選択肢の1つとしてS3のStatic Website Hostingがあります。
今回は独自ドメインでアクセスさせたいときやプライベート空間でアクセスさせたいときに使用できる例としてEKSを経由する方法を紹介します。

概観は次のようになります。ALB Ingress ControllerとNGINX Ingress Controllerを共存させる理由は後述します。

20200621_eks_s3.png

環境情報

macOS Mojave 10.14.6
EKS 1.16
Helm 2.14.3

手順

ここでは手順を説明していきます。EKSとHelm Tillerは既に構築済みであるものとします。

1. S3バケットの作成

今回はstatic-website-test01という名前でS3バケットを作成します。

次にプロパティからStatic Website Hostingの設定を行います。

スクリーンショット 2020-06-21 22.46.42.png

バケットポリシーはEKSと同一のVPCからのアクセスを許可するようにします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::static-website-test01/*",
            "Condition": {
                "StringEquals": {
                    "aws:sourceVpc": "vpc-XXXXXXXX"
                }
            }
        }
    ]
}

またS3バケットに次のファイルをアップロードしておきます。

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>S3 Static Website</title>
  </head>
  <body>
    <h1>S3 Static Website</h1>
  </body>
</html>

2. VPC Endpointの作成

AWSコンソールから作成します。
VPCはEKSと同一のものを選択します。ポリシーは特に制限をかけません。

{
    "Statement": [
        {
            "Action": "*",
            "Effect": "Allow",
            "Resource": "*",
            "Principal": "*"
        }
    ]
}

3. Ingress Controllerのデプロイ

ALB1つで対応するためにALB Ingress ControllerとNGINX Ingress Controllerを用意します。
その際kube2iamを用いてALB Ingress ControllerがALBを作成できるようにします。
デプロイはhelmfileを使用します。

helmfile.yaml
repositories:
  - name: stable
    url: https://kubernetes-charts.storage.googleapis.com
  - name: incubator
    url: https://kubernetes-charts-incubator.storage.googleapis.com

releases:
  # https://github.com/helm/charts/tree/master/stable/kube2iam
  - name: kube2iam
    namespace: kube-system
    chart: stable/kube2iam
    version: 2.0.1
    wait: true
    values:
      - host:
          iptables: true
          interface: eni+
        extraArgs:
          auto-discover-base-arn: ""
        rbac:
          create: true
  # https://github.com/helm/charts/tree/master/incubator/aws-alb-ingress-controller
  - name: alb-ingress-controller
    namespace: kube-system
    chart: incubator/aws-alb-ingress-controller
    version: 0.1.11
    wait: true
    values:
      - clusterName: <CLUSTER-NAME>
        autoDiscoverAwsRegion: true
        autoDiscoverAwsVpcID: true
        rbac:
          serviceAccountAnnotations: 
            iam.amazonaws.com/role: arn:aws:iam::XXXXXXXXXX:role/alb-ingress-controller
  # https://github.com/helm/charts/tree/master/stable/nginx-ingress
  - name: nginx-ingress
    namespace: kube-system
    chart: stable/nginx-ingress
    version: 1.39.0
    wait: true
    values:
      - controller:
          service:
            type: NodePort

次のコマンドでデプロイします。

$ helmfile apply

4. Ingress, Serviceのデプロイ

ALBを作成するためにALB Ingress Controllerに読み込ませるためのIngressをデプロイします。
spec.rules[].hostを定義せずに、全リクエストをNGINX Ingress Controllerに飛ばすようにします。
また、annotationsのalb.ingress.kubernetes.io/schemeの値はpublicかprivateかで変わってくることに注意しましょう。

alb-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    kubernetes.io/ingress.class: alb
  name: alb-ingress
  namespace: kube-system
spec:
  rules:
  - http:
      paths:
      - backend:
          serviceName: nginx-ingress-controller
          servicePort: 80

NGINX Ingress Controllerに読み込ませるIngressを作成します。
ポイントはannotationsにnginx.ingress.kubernetes.io/upstream-vhostを付けてホストヘッダを変えることです。
これは、S3バケット毎にIngressリソースが必要になることを示しています。
このことを考慮しALB Ingress ControllerとNGINX Ingress Controllerを組み合わせて、ALBやCLBの複数作成を防いでいます。

nginx-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/upstream-vhost: static-website-test01.s3-website-ap-northeast-1.amazonaws.com
  name: nginx-ingress
  namespace: default
spec:
  rules:
  - host: s3.sample.com
    http:
      paths:
      - backend:
          serviceName: s3-static-website
          servicePort: 80

ExternalName ServiceでS3バケットのエンドポイントを指定します。

externalname-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: s3-static-website
  namespace: default
spec:
  type: ExternalName
  externalName: static-website-test01.s3-website-ap-northeast-1.amazonaws.com

次のコマンドでデプロイします。

$ kubectl apply -f alb-ingress.yaml
$ kubectl apply -f nginx-ingress.yaml
$ kubectl apply -f externalname-service.yaml

あとは、Route53などでnginx-ingress.yamlで定義したs3.sample.comの名前解決を行いALBに転送されるよう設定します。

確認

試しにブラウザからS3バケットのエンドポイントに直接アクセスしようとしても、公開されていないので拒否されることが確認できます。

スクリーンショット 2020-06-21 22.50.02.png

次にIngressで定義した独自ドメインでアクセスします。
index.htmlが表示されることが分かります。

スクリーンショット 2020-06-22 0.06.18.png

まとめ

EKSを経由してS3 Static Websiteにアクセスできることを確認しました。
S3バケットを公開しない方法の1つとして使用できる構成かと思います。
セキュリティを上げるためにNGINX Ingress ControllerにBasic認証を付けるのも良いかもしれません。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした