Kubernetes Basics

Kubernetesの基礎

Support HackTricks and get benefits!

このページの元の著者は Jorge (彼の元の投稿は こちら)

アーキテクチャと基礎

Kubernetesは何をするのか?

  • コンテナエンジンでコンテナを実行することができます。

  • スケジュールにより、コンテナのミッションを効率的に行うことができます。

  • コンテナを生きたままに保つことができます。

  • コンテナ間の通信を可能にします。

  • デプロイメントの技術を可能にします。

  • 大量の情報を処理します。

アーキテクチャ

  • ノード: ポッドまたはポッドを持つオペレーティングシステム。

  • ポッド: 1つのアプリケーションのみを含むべきです(通常、1つのコンテナのみを実行するため、ポッドはコンテナ技術の実行方法を抽象化するためのものです)。

  • サービス: 各ポッドは、ノードの内部範囲から1つの内部IPアドレスを持っています。ただし、サービスを介しても公開できます。サービスにもIPアドレスがあり、その目的はポッド間の通信を維持することです。したがって、1つのポッドが死んだ場合、新しい置き換え(異なる内部IPを持つ)は、サービスの同じIPでアクセス可能になります。内部または外部として設定できます。サービスは、2つのポッドが同じサービスに接続されている場合にロードバランサーとして機能します。 サービス作成されると、実行中の各サービスのエンドポイントを見つけることができます kubectl get endpoints

  • Kubelet: プライマリノードエージェント。ノードとkubectlの間の通信を確立し、ポッドのみを実行できます(APIサーバーを介して)。Kubeletは、Kubernetesによって作成されていないコンテナを管理しません。

  • Kube-proxy: apiserverとノード間の通信(サービス)を担当するサービスです。ノードのIPテーブルをベースにしています。経験豊富なユーザーは、他のベンダーからの他のkube-proxyをインストールすることができます。

  • サイドカーコンテナ: サイドカーコンテナは、ポッド内のメインコンテナと一緒に実行する必要があるコンテナです。このサイドカーパターンは、現在のコンテナの機能を拡張および強化するものです。現在、アプリケーションをどこでも実行するためにコンテナ技術を使用して依存関係をすべてラップすることを知っています。コンテナは1つのことだけを行い、そのことを非常によく行います。

  • マスタープロセス:

  • APIサーバー: ユーザーとポッドがマスタープロセスと通信するための方法です。認証されたリクエストのみが許可されるべきです。

  • スケジューラ: スケジューリングは、Kubeletが実行できるように、ポッドがノードにマッチングされることを確認することを指します。スケジューラは、より多くの利用可能なリソースを持つノードを決定し、新しいポッドをそれに割り当てるための十分な知識を持っています。スケジューラは新しいポッドを起動するのではなく、ノード内で実行されているKubeletプロセスと通信するだけです。

  • Kube Controller Manager: レプリカセットやデプロイメントなどのリソースをチェックし、正しい数のポッドやノードが実行されているかどうかを確認します。ポッドが欠落している場合、スケジューラと通信して新しいポッドを起動します。これにより、APIへのレプリケーション、トークン、およびアカウントサービスの制御が可能になります。

  • etcd: データストレージ、永続的で一貫性のある分散データベースです。Kubernetesのデータベースであり、クラスターの完全な状態を保持するためのキーバリューストレージです(変更はすべてここに記録されます)。スケジューラやコントローラマネージャなどのコンポーネントは、変更が発生したことを知るためにこのデータに依存します(ノードの利用可能なリソース、実行中のポッドの数など)。

  • クラウドコントローラーマネージャ: AWSやOpenStackなどのクラスターがある場合、フローコントロールとアプリケーションのための特定のコントローラーです。

ノードが複数ある場合(複数のポッドを実行している場合)、アクセス先のApiサーバーは負荷分散され、etcdは同期されることに注意してください。

ボリューム:

ポッドが消えても失われてはならないデータを作成する場合、物理ボリュームに保存する必要があります。Kubernetesは、データを永続化するためにボリュームをポッドにアタッチすることを許可します。ボリュームはローカルマシンまたはリモートストレージにある場合があります。異なる物理ノードでポッドを実行している場合は、リモートストレージを使用する必要があります。

その他の設定:

  • ConfigMap: サービスにアクセスするためのURLを設定できます。ポッドは、他のサービス(ポッド)との通信方法を知るためにここからデータを取得します。ただし、

PKIインフラストラクチャ - 証明書機関 CA:

  • CAはクラスタ内のすべての証明書の信頼されたルートです。

  • コンポーネント同士の相互検証を可能にします。

  • クラスタのすべての証明書はCAによって署名されます。

  • ETCdには独自の証明書があります。

  • タイプ:

  • apiserver証明書。

  • kubelet証明書。

  • スケジューラ証明書。

基本的な操作

Minikube

Minikubeは、完全なKubernetes環境を展開する必要なく、Kubernetes上でいくつかのクイックテストを実行するために使用できます。マスターとノードプロセスを1つのマシンで実行します。Minikubeは、ノードを実行するためにvirtualboxを使用します。ここでインストール方法を確認してください

$ minikube start
😄  minikube v1.19.0 on Ubuntu 20.04
✨  Automatically selected the virtualbox driver. Other choices: none, ssh
💿  Downloading VM boot image ...
> minikube-v1.19.0.iso.sha256: 65 B / 65 B [-------------] 100.00% ? p/s 0s
> minikube-v1.19.0.iso: 244.49 MiB / 244.49 MiB  100.00% 1.78 MiB p/s 2m17.
👍  Starting control plane node minikube in cluster minikube
💾  Downloading Kubernetes v1.20.2 preload ...
> preloaded-images-k8s-v10-v1...: 491.71 MiB / 491.71 MiB  100.00% 2.59 MiB
🔥  Creating virtualbox VM (CPUs=2, Memory=3900MB, Disk=20000MB) ...
🐳  Preparing Kubernetes v1.20.2 on Docker 20.10.4 ...
▪ Generating certificates and keys ...
▪ Booting up control plane ...
▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by defaul

$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured

---- ONCE YOU HAVE A K8 SERVICE RUNNING WITH AN EXTERNAL SERVICE -----
$ minikube service mongo-express-service
(This will open your browser to access the service exposed port)

$ minikube delete
🔥  Deleting "minikube" in virtualbox ...
💀  Removed all traces of the "minikube" cluster

Kubectlの基本

**Kubectl**は、Kubernetesクラスターのためのコマンドラインツールです。これは、KubernetesのマスタープロセスのApiサーバーと通信して、Kubernetesでのアクションを実行したりデータを要求したりします。

kubectl version #Get client and server version
kubectl get pod
kubectl get services
kubectl get deployment
kubectl get replicaset
kubectl get secret
kubectl get all
kubectl get ingress
kubectl get endpoints

#kubectl create deployment <deployment-name> --image=<docker image>
kubectl create deployment nginx-deployment --image=nginx
#Access the configuration of the deployment and modify it
#kubectl edit deployment <deployment-name>
kubectl edit deployment nginx-deployment
#Get the logs of the pod for debbugging (the output of the docker container running)
#kubectl logs <replicaset-id/pod-id>
kubectl logs nginx-deployment-84cd76b964
#kubectl describe pod <pod-id>
kubectl describe pod mongo-depl-5fd6b7d4b4-kkt9q
#kubectl exec -it <pod-id> -- bash
kubectl exec -it mongo-depl-5fd6b7d4b4-kkt9q -- bash
#kubectl describe service <service-name>
kubectl describe service mongodb-service
#kubectl delete deployment <deployment-name>
kubectl delete deployment mongo-depl
#Deploy from config file
kubectl apply -f deployment.yml

Minikube ダッシュボード

ダッシュボードを使用すると、minikubeが実行している内容を簡単に確認できます。アクセスするためのURLは以下の場所にあります:

minikube dashboard --url


🔌  Enabling dashboard ...
▪ Using image kubernetesui/dashboard:v2.3.1
▪ Using image kubernetesui/metrics-scraper:v1.0.7
🤔  Verifying dashboard health ...
🚀  Launching proxy ...
🤔  Verifying proxy health ...
http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

YAML設定ファイルの例

各設定ファイルには3つのパートがあります: metadata(メタデータ)、specification(起動する必要があるもの)、status(望ましい状態)。 デプロイメント設定ファイルのspecificationの中には、実行するイメージを定義する新しい構成構造で定義されたテンプレートが含まれています。

同じ設定ファイルで宣言されたデプロイメント+サービスの例(こちらから)

サービスは通常、1つのデプロイメントに関連しているため、同じ設定ファイルで両方を宣言することができます(この設定で宣言されたサービスは内部からのみアクセス可能です)。

apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb-deployment
labels:
app: mongodb
spec:
replicas: 1
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: mongo
ports:
- containerPort: 27017
env:
- name: MONGO_INITDB_ROOT_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-username
- name: MONGO_INITDB_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-secret
key: mongo-root-password
---
apiVersion: v1
kind: Service
metadata:
name: mongodb-service
spec:
selector:
app: mongodb
ports:
- protocol: TCP
port: 27017
targetPort: 27017

外部サービスの設定の例

このサービスは外部からアクセス可能です(nodePorttype: LoadBalancer属性を確認してください):

---
apiVersion: v1
kind: Service
metadata:
name: mongo-express-service
spec:
selector:
app: mongo-express
type: LoadBalancer
ports:
- protocol: TCP
port: 8081
targetPort: 8081
nodePort: 30000

これはテストには便利ですが、本番環境では内部サービスのみと、アプリケーションを公開するためのIngressを持つべきです。

Ingress設定ファイルの例

これにより、アプリケーションが http://dashboard.com で公開されます。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-ingress
namespace: kubernetes-dashboard
spec:
rules:
- host: dashboard.com
http:
paths:
- backend:
serviceName: kubernetes-dashboard
servicePort: 80

シークレット設定ファイルの例

パスワードがB64でエンコードされていることに注意してください(これは安全ではありません!)

apiVersion: v1
kind: Secret
metadata:
name: mongodb-secret
type: Opaque
data:
mongo-root-username: dXNlcm5hbWU=
mongo-root-password: cGFzc3dvcmQ=

ConfigMapの例

ConfigMapは、ポッドに与えられる設定であり、他のサービスの場所を特定し、アクセスする方法をポッドに知らせるために使用されます。この場合、各ポッドは、mongodb-serviceという名前が、通信できるポッドのアドレスであることを知っています(このポッドはmongodbを実行しています):

apiVersion: v1
kind: ConfigMap
metadata:
name: mongodb-configmap
data:
database_url: mongodb-service

次に、デプロイメント設定内でこのアドレスを指定することで、ポッドの環境変数に読み込まれるようになります。

[...]
spec:
[...]
template:
[...]
spec:
containers:
- name: mongo-express
image: mongo-express
ports:
- containerPort: 8081
env:
- name: ME_CONFIG_MONGODB_SERVER
valueFrom:
configMapKeyRef:
name: mongodb-configmap
key: database_url
[...]

ボリューム設定の例

https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumesには、さまざまなストレージ設定のyamlファイルの例があります。 ボリュームは名前空間の内部にありません

名前空間

Kubernetesは、同じ物理クラスタをバックエンドとする複数の仮想クラスタをサポートしています。これらの仮想クラスタは名前空間と呼ばれます。これらは、多くのユーザーが複数のチームまたはプロジェクトに分散している環境で使用することを想定しています。数人から数十人のユーザーがいるクラスタでは、名前空間を作成したり考えたりする必要はありません。Kubernetesで展開されたアプリケーションの各部分をより良く制御し、組織化するために名前空間を使用する必要があります。

名前空間は名前のスコープを提供します。リソースの名前は名前空間内で一意である必要がありますが、名前空間間では一意である必要はありません。名前空間は互いにネストすることはできず、Kubernetesリソース1つの名前空間にのみ存在できます。

minikubeを使用している場合、デフォルトで4つの名前空間があります。

kubectl get namespace
NAME              STATUS   AGE
default           Active   1d
kube-node-lease   Active   1d
kube-public       Active   1d
kube-system       Active   1d
  • kube-system: ユーザーが使用することを意図されていないため触れないでください。マスターとkubectlプロセス用です。

  • kube-public: 公開可能なデータです。クラスター情報を含むコンフィグマップが含まれています。

  • kube-node-lease: ノードの可用性を決定します。

  • default: ユーザーがリソースを作成するために使用する名前空間です。

#Create namespace
kubectl create namespace my-namespace

ほとんどのKubernetesリソース(例:ポッド、サービス、レプリケーションコントローラなど)は、いくつかの名前空間に存在します。ただし、名前空間リソースやノード、永続ボリュームなどの低レベルリソースなど、他のリソースは名前空間に存在しません。Kubernetesリソースが名前空間に存在するかどうかを確認するには、次の手順を実行します:

kubectl api-resources --namespaced=true #In a namespace
kubectl api-resources --namespaced=false #Not in a namespace

そのコンテキストで、すべての後続のkubectlコマンドのために名前空間を保存することができます。

kubectl config set-context --current --namespace=<insert-namespace-name-here>

Helm

HelmはKubernetesのパッケージマネージャーです。YAMLファイルをパッケージ化し、公開およびプライベートのリポジトリで配布することができます。これらのパッケージはHelmチャートと呼ばれます。

helm search <keyword>

Helmは変数を使用して設定ファイルを生成することができるテンプレートエンジンです。

Kubernetesのシークレット

シークレットは、パスワード、トークン、キーなどの機密データを含むオブジェクトです。このような情報は通常、Podの仕様やイメージに配置されます。ユーザーはシークレットを作成することもできますし、システムもシークレットを作成します。シークレットオブジェクトの名前は有効なDNSサブドメイン名である必要があります。公式ドキュメントを参照してください。

シークレットには以下のようなものがあります:

  • API、SSHキー。

  • OAuthトークン。

  • 資格情報、パスワード(平文またはb64 + 暗号化)。

  • 情報やコメント。

  • データベース接続コード、文字列など。

Kubernetesにはさまざまなタイプのシークレットがあります。

組み込みタイプ使用法

Opaque

ユーザー定義の任意のデータ(デフォルト)

kubernetes.io/service-account-token

サービスアカウントトークン

kubernetes.io/dockercfg

シリアル化された~/.dockercfgファイル

kubernetes.io/dockerconfigjson

シリアル化された~/.docker/config.jsonファイル

kubernetes.io/basic-auth

基本認証の資格情報

kubernetes.io/ssh-auth

SSH認証の資格情報

kubernetes.io/tls

TLSクライアントまたはサーバーのデータ

bootstrap.kubernetes.io/token

ブートストラップトークンデータ

Opaqueタイプはデフォルトのタイプであり、ユーザーによって定義される典型的なキーと値のペアです。

シークレットの動作方法:

次の設定ファイルは、username: YWRtaW4=password: MWYyZDFlMmU2N2Rmの2つのキーと値のペアを持つmysecretというシークレットを定義しています。また、secretpodというポッドも定義されており、mysecretで定義されたusernamepassword環境変数SECRET_USERNAMESECRET_PASSWORDで公開されます。さらに、usernameシークレットをmysecret内のパス/etc/foo/my-group/my-username0640のパーミッションでマウントします。

secretpod.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: MWYyZDFlMmU2N2Rm
---
apiVersion: v1
kind: Pod
metadata:
name: secretpod
spec:
containers:
- name: secretpod
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
volumeMounts:
- name: foo
mountPath: "/etc/foo"
restartPolicy: Never
volumes:
- name: foo
secret:
secretName: mysecret
items:
- key: username
path: my-group/my-username
mode: 0640
kubectl apply -f <secretpod.yaml>
kubectl get pods #Wait until the pod secretpod is running
kubectl exec -it  secretpod -- bash
env | grep SECRET && cat /etc/foo/my-group/my-username && echo

etcd内のシークレット

etcdは、Kubernetesのバックエンドストアとして使用される一貫性のある高可用性のキーバリューストアです。etcdに保存されているシークレットにアクセスしましょう。

cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd

以下は、/hive/hacktricks-cloud/pentesting-cloud/kubernetes-security/kubernetes-basics.md ファイルからのコンテンツです。訳文を提供しますが、コード、ハッキング技術の名前、ハッキング用語、クラウド/SaaSプラットフォームの名前(Workspace、aws、gcpなど)、'leak'という単語、pentesting、およびマークダウンタグなどは翻訳しないでください。また、翻訳とマークダウンの構文以外の追加の要素は追加しないでください。

You will see certs, keys and url’s were are located in the FS. Once you get it, you would be able to connect to etcd.
<p>You will see certs, keys and url’s were are located in the FS. Once you get it, you would be able to connect to etcd.</p>

訳文:

FSには証明書、キー、およびURLが配置されています。これらを取得すると、etcdに接続できるようになります。
<p>FSには証明書、キー、およびURLが配置されています。これらを取得すると、etcdに接続できるようになります。</p>
#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] health

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] health

通信を確立すると、シークレットを取得することができます。

#ETCDCTL_API=3 etcdctl --cert <path to client.crt> --key <path to client.ket> --cacert <path to CA.cert> endpoint=[<ip:port>] get <path/to/secret>

ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/apiserver-etcd-client.crt --key /etc/kubernetes/pki/apiserver-etcd-client.key --cacert /etc/kubernetes/pki/etcd/etcd/ca.cert endpoint=[127.0.0.1:1234] get /registry/secrets/default/secret_02

ETCDへの暗号化の追加

デフォルトでは、etcd内のすべてのシークレットは平文で保存されます。ただし、暗号化レイヤーを適用しない限り、これは変わりません。以下の例は、https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/を基にしています。

encryption.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
- identity: {}

その後、作成した設定ファイルの場所を指すように、kube-apiserver--encryption-provider-config フラグを設定する必要があります。/etc/kubernetes/manifest/kube-apiserver.yaml を編集し、以下の行を追加します:

containers:
- command:
- kube-apiserver
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>

volumeMounts の中をスクロールダウンしてください:

- mountPath: /etc/kubernetes/etcd
name: etcd
readOnly: true

ボリュームマウントの中で、hostPathにスクロールダウンしてください。

- hostPath:
path: /etc/kubernetes/etcd
type: DirectoryOrCreate
name: etcd

データが暗号化されていることの確認

データはetcdに書き込まれる際に暗号化されます。kube-apiserverを再起動した後、新しく作成されたまたは更新されたシークレットは、保存される際に暗号化されるはずです。確認するために、etcdctlコマンドラインプログラムを使用してシークレットの内容を取得できます。

  1. defaultネームスペースにsecret1という新しいシークレットを作成します:

kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
  1. etcdctlコマンドラインを使用して、etcdからそのシークレットを読み取ります:

ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C

[...]はetcdサーバーに接続するための追加の引数である必要があります。

  1. 保存されたシークレットがk8s:enc:aescbc:v1:で始まることを確認します。これは、aescbcプロバイダーが結果のデータを暗号化したことを示しています。

  2. API経由で取得した際にシークレットが正しく復号化されていることを確認します:

kubectl describe secret secret1 -n default

mykey: bXlkYXRhと一致するはずです。mydataはエンコードされています。シークレットを完全にデコードするには、シークレットのデコードを確認してください。

シークレットは書き込み時に暗号化されるため、シークレットの更新を行うとその内容が暗号化されます。

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

最終的なヒント:

参考文献

ハックトリックスをサポートして特典を得る!

最終更新