ry's Tech blog

Cloud Native技術などについて書いていきます。

Kubenews #29

2021-08-20

youtu.be

Encrypt your Kubernetes Secrets with Mozilla SOPS (click here to source)

Kubernetes Secretsは、base64で暗号化されていて、簡単に複合化できてしまう。 そのソリューションとして、Mozilla SOPSがある。

github : SOPS

・特徴

  • yaml, json, ini, binaryなどに対応

  • 以下のようなSolutionと連携が可能

    • PGP
    • Azure Key Vault
    • AWS KMS
    • GCP KMS
    • HashiCorp Vault

この記事では、Azureに関しての例が書かれており、Azure Service Principal (SP) を使うことを推奨しています。

  • Provision an Azure Service Principal (SP)
# create a service principal
az ad sp create-for-rbac -n sp-sops-keyvault -o json
# {
#   "appId": "00000000-0000-0000-000000000000",
#   "displayName": "http://sp-sops-keyvault",
#   "name": "http://sp-sops-keyvault",
#   "password": "00000000-0000-0000-000000000000",
#   "tenant": "<your_tenant_identifier>
# }

export AZURE_CLIENT_ID=<appId>
export AZURE_CLIENT_SECRET=<password>
export AZURE_TENANT_ID=<tenant>
  • Provisioning an Azure Key Vault instance
# create a new Resource Group
az group create -n rg-sops-sample -l germanywestcentral

# create a Key Vault instance
az keyvault create -n kv-sops-sample \
   -g rg-sops-sample \
   -l germanywestcentral 

# create an access policy for the SP
az keyvault set-policy -n kv-sops-sample \
   -g rg-sops-sample \
   --spn $AZURE_CLIENT_ID \
   --key-permissions encrypt decrypt
  • Create a key in Azure Key Vault for encryption & decryption
# create an key for encryption / decryption 
az keyvault key create -n sops-sample-key \
    --vault-name kv-sops-sample \
    --ops encrypt decrypt \
    --protection software

# read and store key identifier
export KEY_ID=$(az keyvault key show -n sops-sample-key \
    --vault-name kv-sops-sample \
    --query key.kid -o tsv)
# download sops cli for macOS
curl -O -L -C - https://github.com/mozilla/sops/releases/download/v3.7.1/sops-v3.7.1.darwin

# move and rename the cli to /usr/bin
sudo mv sops-v3.7.1.darwin /usr/bin/sops

# make it executable
sudo chmod +x /usr/bin/sops

まず、Sercretを作成します。

# create the Kubernetes secret
kubectl create secret generic demo \
    --from-literal mysecret=secret_value \
    -o yaml \
    --dry-run=client > secret.encoded.yml

# print the contents of secret.encoded.yml
cat secret.encoded.yml

# apiVersion: v1
# data:
#   mysecret: c2VjcmV0X3ZhbHVl
# kind: Secret
# metadata:
#   creationTimestamp: null
#   name: demo

sopsコマンドを用いて、暗号化します。

# encrypt secret.encoded.yml using SOPS
sops --encrypt --encrypted-regex '^(data|stringData)$' \
    --azure-kv $KEY_ID secret.encoded.yml > secret.encrypted.yml

# print the contents of secret.encrypted.yml
cat secret.encrypted.yml

# apiVersion: v1
# data:
#    mysecret: ENC[AES256_GCM,data:gz/WAjWte3bCnNm6e+G4ow==,iv:VB4pAv833tDdD4n76h4CqEZNpGdwA3V1QGWp7PK/Jfc=,tag:CcUy3rti4XcWArmHANVS8Q==,type:str]
# kind: Secret
# metadata:
#     creationTimestamp: null
#     name: demo
# sops:
#     kms: []
#     gcp_kms: []
#     azure_kv:
#         - vault_url: https://kv-sops-sample.vault.azure.net
#           name: sops-sample-key
#           version: ee44c0c0cc9e4620aa4f4c86c4942047
#           created_at: "2021-08-02T20:55:40Z"
#           enc: EjszDACgiDP8rW3wzs-7fAmFzlAhCq0-R9YlA9cuPcq78EXEeNTC8OnlSdXQAGdGrgE9oylu1HKZa4RB9GxzzVDav8uNVPp67NPmC4-teeA5iRE4jqlp1An6sG6CpkZGcAmKWpfj_DEWecqrNGWSLTA2hI_HKwG5xNkFh9Myik6732W-XL65IFqgepcFrNIzeHetznO0j1iISNXqMeJjeCnZ6Qq0jcXUMIfQnXjAllKfjSukiT3A3GlWxP0j50Z328t-JHi5RowYHT-hC8FDOdR_U95sqnFd27RgEXmbDIU6IGvP3vmCiZJz4YQCPXaGhySvFY6qCEoCbCSC4RaoWw
#     hc_vault: []
#     age: []
#     lastmodified: "2021-08-02T20:55:41Z"
#     mac: ENC[AES256_GCM,data:AmKRnzoImfIzPa3JBcuxUKRrse5uZwJGukpLj1wxed3R7lsUN+QAV1+WkfNyeMoW5C3ek7j20Xpbvzi+MgP8zcQOwWSwA79Svgz3hKMn9eTRTfgU+4jYezIIHCwkv61MTN8RGW5AhOInYP8oRPW3zKD+SbBO/Jeu7SC+/oVn07I=,iv:S4Th+0quL84lhJtA/lugEv+iLc+WhWEYPSlXGWKhd/M=,tag:CUGg8+UM7gNSzfjJx1Ua1w==,type:str]
#     pgp: []
#     encrypted_regex: ^(data|stringData)$
#     version: 3.7.1

# delete encoded version of the secret
rm secret.encoded.yml

# add encrypted secret to source control and commit it
git add secret.encrypted.yml
git commit -m 'chore: add encrypted secret'

sopsコマンドを用いて複合化ができます。

# decrypt and deploy the secret
sops --decrypt secret.encrypted.yml | kubectl apply -f -

いつものSecret同様、Pod等から参照が可能です。

apiVersion: v1
kind: Pod
metadata:
  name: echo
  labels:
    app: echo
spec:
    containers:
    - image: thorstenhans/env-via-http:0.0.1
      name: main
      ports:
        - containerPort: 5000
          protocol: TCP
      envFrom:
        - secretRef:
            name: demo
            optional: true
      resources:
        requests:
          cpu: 50m
          memory: 32Mi
        limits:
          cpu: 100m
          memory: 48Mi 

Implementing traffic policies in Kubernetes (click here to source)

Kumaを使用したKubernetesトラフィックポリシーの設計について

2つのバックエンドサービスは外部ネットワークから分離した状態で、ある1つのサービスからの通信を許可したい場合、以下のようなポリシーを適用できる。

cat <<EOF | kumactl apply -f - 
type: TrafficPermission
name: api-to-backends
mesh: default
sources:
  - match:
      service: 'publicAPI'
destinations:
  - match:
      service: 'backend1'
  - match:
      service: 'backend2'
EOF

How to Run HAProxy with Docker (click here to source)

Dockerの実行によるパフォーマンスへの影響

Dockerを使用すると、ホストへのブリッジネットワークを作成することで、コンテナー内で実行されているサービスにアクセスできます。

よって、コンテナのローカルネットワークとホストのブリッジネットワーク間でネットワークアドレス変換(NAT)をするため、遅延が発生します。

前に引用した同じIBMの調査では、DockerのNATによって、クライアントからの100バイトの要求とアプリケーションからの200バイトの応答のレイテンシーが約35 µsから70 µsに倍増されたらしい。

非常に低いレイテンシが必要な場合は、Dockerのホストネットワーク機能の使用に切り替えることで、コンテナはホストと同じネットワークを共有できるため、NATの必要性がなくなります。

Dockerを実行する際のセキュリティに関する考慮事項

HAProxyは、80や443などの制限されたTCPポートにバインドする必要があるため、rootアクセスが必要です。

ただし、起動が完了すると、root権限が削除され、非特権ユーザーとして実行されます。

DockerでHAProxyを実行する

3つのアプリケーションを動かします。

$ sudo docker network create --driver=bridge mynetwork

$ sudo docker run -d \
   --name web1 --net mynetwork jmalloc/echo-server:latest
   
$ sudo docker run -d \
   --name web2 --net mynetwork jmalloc/echo-server:latest
   
$ sudo docker run -d \
   --name web3 --net mynetwork jmalloc/echo-server:latest

$ sudo docker ps

CONTAINER ID   IMAGE                        COMMAND              CREATED              STATUS              PORTS      NAMES
98216bb8c5ff   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web3
ae6accc111d9   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web2
554fafbc2b3b   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web1

HAProxyロードバランサーを介してこれらのコンテナーにトラフィックを中継できるよう、現在のディレクトリにhaproxy.cfgという名前のファイルを作成し、それに以下を追加します。

global
  stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
  log stdout format raw local0 info

defaults
  mode http
  timeout client 10s
  timeout connect 5s
  timeout server 10s
  timeout http-request 10s
  log global

frontend stats
  bind *:8404
  stats enable
  stats uri /
  stats refresh 10s

frontend myfrontend
  bind :80
  default_backend webservers

backend webservers
  server s1 web1:8080 check
  server s2 web2:8080 check
  server s3 web3:8080 check
  • 最初のフロントエンドはポート8404でリッスンし、HAProxy Statsダッシュボードを有効にします。このダッシュボードには、ロードバランサーに関するライブ統計が表示されます。

  • もう一方のフロントエンドはポート80でリッスンし、Webサーバーのバックエンドにリストされている3つのWebアプリケーションの1つに要求をディスパッチします。

以下のコマンドで、HAProxyを作成します。

$ sudo docker run -d \
   --name haproxy \
   --net mynetwork \
   -v $(pwd):/usr/local/etc/haproxy:ro \
   -p 80:80 \
   -p 8404:8404 \
   haproxytech/haproxy-alpine:2.4

Kubernetes CI/CD with Tekton and ArgoCD (click here to source)

TektonとArgoCDを使用してKubernetesでCI / CDプロセスを構成する方法が書かれています。

AWS App MeshとIstioの比較 (click here to source)

AWSが提供するサービスメッシュのマネージドサービスであるApp MeshとIstioの比較について書かれています。

比較項目としてはいかがあります。

  • ECS環境での利用
  • トラフィックルーティング
  • 障害分離(タイムアウト、リトライ、サーキットブレーカー)
  • Ingress
  • セキュリティ機能
  • オブザーバビリティ関連の機能

OPA GatekeeperによるKubernetesセキュリティの歩き方 (click here to source)

以下のような、運用をしていく中でこういったことに注意したなどの事例を基に説明されている。

ConstraintとConstraintTemplateを何も考えずにクラスタに適用してしまうと、意図していないリソースまでも影響を受ける可能性があります。

enforcementAction: dryrunを使用し、一定期間様子を見ながら適用することをおすすめします