Exposing Services in Kubernetes

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

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プロキシを使用してアクセスすることができます:

kubectl proxy --port=8080

今、Kubernetes APIを介してサービスにアクセスするために、次のスキームを使用できます:

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

例えば、次のURLを使用することができます:

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

このサービスにアクセスするために:

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認証済みユーザーとして実行する必要があります。

NodePort

NodePortは、すべてのノード(VM)で特定のポートを開き、このポートに送信されるトラフィックをサービスに転送します。通常、これは非常に悪いオプションです。

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

もしyamlでnodePortを指定しない場合(これは開かれるポートです)、30000から32767の範囲のポートが使用されます

LoadBalancer

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

ServiceごとにLoadBalancerを支払う必要があり、費用がかかる場合があります。

ExternalName

ExternalNameタイプのServiceは、Serviceを通常のセレクタ(my-servicecassandraなど)ではなく、DNS名にマップします。これらのServiceは、spec.externalNameパラメータで指定します。

たとえば、次のService定義は、prodネームスペースのmy-service 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レベルで発生するということです。プロキシやフォワーディングではなく、DNSレベルでリダイレクションが行われます。

外部IP

クラスタに入ってくるトラフィックは、外部IP宛先IP)を使用して、Serviceポートにルーティングされ、Serviceのエンドポイントの1つに転送されます。externalIPsはKubernetesでは管理されず、クラスタ管理者の責任です。

Serviceの仕様では、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

Ingress(イングレス)

上記の例とは異なり、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

参考文献

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

最終更新