Exposing Services in Kubernetes

HackTricksのサポート

Kubernetesでサービスを公開する方法には、内部エンドポイントと外部エンドポイントの両方がアクセスできるようにするためのさまざまな方法があります。このKubernetesの構成は非常に重要であり、管理者は攻撃者がアクセスすべきでないサービスにアクセス権を与える可能性があります。

自動列挙

公開された方法を列挙する前に、K8sが公開されたものをすべて見つけることができることを知っておくために、名前空間、サービス、イングレスをリストアップできれば、次のコマンドで公開されたすべてを見つけることができます:

kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
kubectl get service -n "$ns"
kubectl get ingress -n "$ns"
echo "=============================================="
echo ""
echo ""
done | grep -v "ClusterIP"
# Remove the last '| grep -v "ClusterIP"' to see also type ClusterIP

ClusterIP

ClusterIPサービスはデフォルトのKubernetes サービスです。これは、クラスター内にある他のアプリがアクセスできるサービスを提供します。外部アクセスはありません

ただし、これはKubernetes Proxyを使用してアクセスできます:

kubectl proxy --port=8080

Now, you can navigate through the Kubernetes API to access services using this scheme:

http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/

For example you could use the following URL:

http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/

to access this service:

apiVersion: v1
kind: Service
metadata:
name: my-internal-service
spec:
selector:
app: my-app
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP

この方法を実行するには、kubectl認証済みユーザーとして実行する必要があります。

すべての ClusterIP をリストします:

kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP

NodePort

NodePortを利用すると、すべてのノード(仮想マシンを表す)に指定されたポートが利用可能になります。この特定のポートに向けられたトラフィックは、その後サービスにシステマティックにルーティングされます。一般的に、この方法は欠点があるため推奨されていません。

すべてのNodePortをリストアップします:

kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort

NodePort仕様の例:

apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
selector:
app: my-app
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30036
protocol: TCP

LoadBalancer

サービスをクラウドプロバイダのロードバランサーを使用して外部に公開します。GKEでは、これによりNetwork Load Balancerが起動され、サービスにすべてのトラフィックを転送する単一のIPアドレスが提供されます。AWSでは、ロードバランサーが起動されます。

公開されたサービスごとにロードバランサーを支払う必要があり、これは高額になる可能性があります。

すべてのロードバランサーをリストアップします:

kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer

外部IP

外部IPは、ロードバランサータイプのサービスによって公開され、一般的には外部クラウドプロバイダーのロードバランサーが使用されている場合に使用されます。

これらを見つけるには、EXTERNAL-IPフィールドに値があるロードバランサーを確認してください。

クラスターに入るトラフィックは、外部IP宛先IPとして)、サービスポートにルーティングされ、サービスのエンドポイントの1つに到達します。externalIPsはKubernetesによって管理されず、クラスター管理者の責任です。

サービスの仕様では、externalIPsServiceTypesのいずれかと共に指定できます。以下の例では、"my-service"は"80.11.12.10:80"(externalIP:port)でクライアントからアクセスできます。

apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10

ExternalName

ドキュメントから: ExternalNameタイプのサービスは、通常のセレクター(my-servicecassandraなど)ではなく、サービスをDNS名にマップします。これらのサービスは、spec.externalNameパラメーターで指定します。

たとえば、次のサービス定義は、prodネームスペース内のmy-serviceサービスをmy.database.example.comにマップします:

apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

ホストmy-service.prod.svc.cluster.localを検索すると、クラスタDNSサービスが値my.database.example.comを持つCNAMEレコードを返します。my-serviceへのアクセスは他のサービスと同様に機能しますが、重要な違いはリダイレクトがプロキシングや転送ではなくDNSレベルで発生することです。

すべてのExternalNamesをリストアップします:

kubectl get services --all-namespaces | grep ExternalName

イングレス

上記の例とは異なり、Ingressはサービスの一種ではありません。代わりに、複数のサービスの前に配置され、"スマートルーター"またはクラスターへの入り口として機能します

Ingressではさまざまなことができ、異なる機能を持つ多くの種類のIngressコントローラーがあります

デフォルトのGKE Ingressコントローラーは、HTTP(S)ロードバランサーを起動します。これにより、パスベースおよびサブドメインベースのルーティングをバックエンドサービスに対して行うことができます。たとえば、foo.yourdomain.comのすべてをfooサービスに送り、yourdomain.com/bar/パスの下のすべてをbarサービスに送ることができます。

GKE上のIngressオブジェクトのYAMLは、L7 HTTPロードバランサーを使用した場合、次のようになります:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: other
servicePort: 8080
rules:
- host: foo.mydomain.com
http:
paths:
- backend:
serviceName: foo
servicePort: 8080
- host: mydomain.com
http:
paths:
- path: /bar/*
backend:
serviceName: bar
servicePort: 8080

すべてのイングレスをリストアップします:

kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'

この場合、それぞれの情報を1つずつ取得して、よりよく読む方が良いです。

kubectl get ingresses --all-namespaces -o=yaml

参考

HackTricksのサポート

Last updated