Exposing Services in Kubernetes

Support HackTricks

쿠버네티스에서 서비스를 노출하는 다양한 방법이 있어 내부 엔드포인트와 외부 엔드포인트가 모두 액세스할 수 있습니다. 이 쿠버네티스 구성은 관리자가 접근해서는 안 되는 서비스에 공격자에게 액세스 권한을 부여할 수 있기 때문에 매우 중요합니다.

자동 열거

공개로 서비스를 노출하는 방법을 열거하기 전에, 네임스페이스, 서비스 및 인그레스를 나열할 수 있다면, 다음 명령어로 공개로 노출된 모든 것을 찾을 수 있습니다:

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

이제 다음 체계를 사용하여 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인증된 사용자로 실행해야 합니다.

모든 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

만약 yaml에서 nodePort지정하지 않으면 (열릴 포트입니다) 30000-32767 범위의 포트가 사용됩니다.

LoadBalancer

클라우드 제공업체의 로드 밸런서를 사용하여 서비스를 외부에 노출합니다. GKE의 경우, 이는 네트워크 로드 밸런서를 생성하여 모든 트래픽을 서비스로 전달할 단일 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는 로드 밸런서 유형의 서비스에 의해 노출되며 일반적으로 외부 클라우드 제공업체 로드 밸런서를 사용할 때 사용됩니다.

외부 IP를 찾으려면 EXTERNAL-IP 필드에 값이 있는 로드 밸런서를 확인하십시오.

외부 IP (대상 IP로) 클러스터로 인입되는 트래픽은 서비스 포트로 라우팅되어 서비스 엔드포인트 중 하나로 전달됩니다. 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-service 또는 cassandra가 아닌 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.comCNAME 레코드를 반환합니다. my-service에 액세스하는 것은 다른 서비스와 동일한 방식으로 작동하지만 중요한 차이점은 리다이렉션이 프록시 또는 포워딩을 통해가 아닌 DNS 레벨에서 발생한다는 것입니다.

모든 ExternalNames를 나열하십시오:

kubectl get services --all-namespaces | grep ExternalName

인그레스

위의 모든 예제와는 달리 인그레스는 서비스 유형이 아닙니다. 대신, 여러 서비스 앞에 위치하여 "스마트 라우터" 또는 클러스터로의 진입점 역할을 합니다.

인그레스를 사용하면 다양한 작업을 수행할 수 있으며, 다양한 기능을 갖춘 여러 유형의 인그레스 컨트롤러가 있습니다.

기본 GKE 인그레스 컨트롤러는 HTTP(S) 로드 밸런서를 생성합니다. 이를 통해 경로 기반 및 서브도메인 기반의 백엔드 서비스 라우팅을 수행할 수 있습니다. 예를 들어, foo.yourdomain.com의 모든 것을 foo 서비스로 보내고, yourdomain.com/bar/ 경로 아래의 모든 것을 bar 서비스로 보낼 수 있습니다.

GKE에서 L7 HTTP 로드 밸런서를 사용하는 인그레스 객체의 YAML은 다음과 같을 수 있습니다:

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'

이 경우에는 각각의 정보를 하나씩 얻어서 더 잘 읽는 것이 좋습니다:

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

참고 자료

HackTricks 지원하기

Last updated