🎃

istioを使って特定のエンドポイントにapi-key認証を組み込む

2023/04/23に公開

構成

  • EKS 1.25
  • istio 1.17

そもそも

  • 認証されていないアプリケーションを公開することになる場合、なにがしかの認証をどこかで仕込む必要がある
  • AWS環境にデプロイしているので、ずっとALBでできるものだと思っていたけどできないということが分かり、せっかくなのでKubernetesの方でやってしまおうというのでそうなった
  • WAF入れていればそれで事足りるだろうし、Lambdaに飛ばすなどやり方はいろいろあるとは思う
  • ちなみに、kubectl port-forwardしたら、api-keyがなくても通過した
    • Pod直接、Service経由両方
    • なので、ingressで試した

手順

インストール

リファレンスに従うと、コマンドラインツールをインストールして、それを使ってクラスタに展開して。ということみたいです。

コマンドライン

curl -L https://istio.io/downloadIstio | sh -
cd istio-1.17.2
export PATH="$PATH:/home/yuta/istio-1.17.2/bin"

bashrcなどに追加してあげるといい

export PATH="$PATH:/home/yuta/istio-1.17.2/bin"

やってみる

リソースインストール

istioctl install --set profile=demo -y

タグ付け

指定したNamespaceにタグ付けをします。
そうすることで、このNamespace上で起動されるPodにサイドカーとして、envoyコンテナが注入されます。
このEnvoyコンテナは、ネットワーク的にサービス用コンテナに割り込む形でProxyとして配置されます。

kubectl label namespace httpbin istio-injection=enabled

サンプルアプリ起動

サンプルとして、簡単なAPIサーバhttpbinを起動するだけのもの

kubectl create ns httpbin
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
  namespace: httpbin
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpbin
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - name: httpbin
        image: kennethreitz/httpbin
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: httpbin
spec:
  selector:
    app: httpbin
  ports:
    - protocol: TCP
      port: 18080
      targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpbin-ingress
  namespace: httpbin
  annotations:
    kubernetes.io/ingress.class: "alb"
    alb.ingress.kubernetes.io/scheme: "internet-facing"
    alb.ingress.kubernetes.io/target-type: "ip"
    external-dns.alpha.kubernetes.io/hostname: httpbin.dev.vamemic.link
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:ap-northeast-1:01111111111111:certificate/0a214c1e-7526-492b-9f4e-111111111111111
spec:
  rules:
  - host: httpbin.dev.vamdemic.link
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: httpbin
            port:
              number: 18080
  tls:
  - hosts:
    - httpbin.dev.vamdemic.link

見れること確認

# curl https://httpbin.dev.vamdemic.link/get -I
HTTP/2 200
date: Sun, 23 Apr 2023 01:13:42 GMT
content-type: application/json
content-length: 436
server: istio-envoy
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 2
x-envoy-decorator-operation: httpbin.httpbin.svc.cluster.local:18080/*

EnvoyFilterをインストール

envoy.yaml

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: x-api-key-filter
  namespace: httpbin
spec:
  workloadSelector:
    labels:
      app: httpbin
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
              subFilter:
                name: "envoy.filters.http.router"
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.lua
          typed_config:
            "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
            inlineCode: |
              function envoy_on_request(request_handle)
                local api_key = request_handle:headers():get("x-api-key")
                if api_key ~= "your_api_key" then
                  request_handle:respond({[":status"] = "403"}, "Invalid x-api-key")
                end
              end

ここで、api-keyの検証をしている

function envoy_on_request(request_handle)
local api_key = request_handle:headers():get("x-api-key")
if api_key ~= "your_api_key" then
  request_handle:respond({[":status"] = "403"}, "Invalid x-api-key")
end
end
kubectl apply -f envoy.yaml

動作チェック

403で返ってくる

curl https://httpbin.dev.vamdemic.link/get
Invalid x-api-key

api-keyを指定してリクエストすると、無事見れるはず。

curl  --header 'Accept: application/json' --header 'X-API-KEY:your_api_key' https://httpbin.dev.vamdemic.link/get

参考

https://istio.io/v1.10/docs/setup/getting-started/#download

Discussion