mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-07-29 07:00:29 -07:00
Translated ['src/pentesting-cloud/kubernetes-security/exposing-services-
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
Kubernetes에서는 **서비스를 노출하는 여러 방법**이 있어서 **internal** 엔드포인트와 **external** 엔드포인트가 모두 접근할 수 있습니다. 이 Kubernetes 설정은 매우 중요합니다. 관리자가 **공격자에게 접근해서는 안 되는 서비스에 대한 접근 권한**을 줄 수 있기 때문입니다.
|
||||
Kubernetes에서 **services를 노출하는 다양한 방법**이 있어 **internal** endpoint와 **external** endpoint 모두가 접근할 수 있습니다. 이 Kubernetes configuration은 상당히 중요합니다. administrator가 **attackers**에게 원래 접근할 수 없어야 하는 services에 대한 access를 줄 수 있기 때문입니다.
|
||||
|
||||
### Automatic Enumeration
|
||||
|
||||
K8s가 서비스를 public에 노출하는 방법을 열거하기 전에, namespaces, services, ingresses를 나열할 수 있다면 public에 노출된 모든 것을 다음으로 찾을 수 있다는 점을 알아두세요:
|
||||
K8s가 public에 services를 노출하는 방법을 알아보기 전에, namespaces, services, ingresses를 list할 수 있다면 다음으로 public에 노출된 모든 것을 찾을 수 있다는 점을 알아두세요:
|
||||
```bash
|
||||
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
|
||||
echo "Namespace: $ns"
|
||||
@@ -20,17 +20,17 @@ done | grep -v "ClusterIP"
|
||||
```
|
||||
### ClusterIP
|
||||
|
||||
**ClusterIP** **service**는 Kubernetes의 **기본** **service**입니다. 클러스터 **내부**에서 다른 앱이 접근할 수 있는 **service inside**를 제공합니다. **외부 접근**은 없습니다.
|
||||
**ClusterIP** service는 Kubernetes **service**의 **기본값**입니다. 클러스터 **내부**에 있는 다른 앱들이 접근할 수 있는 **클러스터 내부 서비스**를 제공합니다. **외부 접근은 없습니다**.
|
||||
|
||||
하지만, 이는 Kubernetes Proxy를 사용하여 접근할 수 있습니다:
|
||||
하지만, Kubernetes Proxy를 사용하면 접근할 수 있습니다:
|
||||
```bash
|
||||
kubectl proxy --port=8080
|
||||
```
|
||||
이제 다음 scheme을 사용해 Kubernetes API를 통해 services에 접근할 수 있습니다:
|
||||
이제 다음 scheme를 사용하여 Kubernetes API를 통해 services에 접근할 수 있습니다:
|
||||
|
||||
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
|
||||
|
||||
예를 들어, 다음 URL을 사용할 수 있습니다:
|
||||
예를 들어 다음 URL을 사용할 수 있습니다:
|
||||
|
||||
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
|
||||
|
||||
@@ -52,19 +52,19 @@ protocol: TCP
|
||||
```
|
||||
_이 방법은 `kubectl`을 **인증된 사용자**로 실행해야 합니다._
|
||||
|
||||
모든 ClusterIP 나열:
|
||||
모든 ClusterIP를 나열하세요:
|
||||
```bash
|
||||
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**가 사용될 때, 지정된 포트가 모든 Node(즉, Virtual Machines)에서 열립니다. 이 특정 포트로 향하는 **Traffic**는 체계적으로 **service로 라우팅**됩니다. 일반적으로 이 방식은 단점 때문에 권장되지 않습니다.
|
||||
When **NodePort** is utilised, a designated port is made available on all Nodes (representing the Virtual Machines). **Traffic** directed to this specific port is then systematically **routed to the service**. Typically, this method is not recommended due to its drawbacks.
|
||||
|
||||
모든 NodePorts 목록:
|
||||
모든 NodePort 나열:
|
||||
```bash
|
||||
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 지정 예시:
|
||||
NodePort specification의 예:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -81,13 +81,24 @@ targetPort: 80
|
||||
nodePort: 30036
|
||||
protocol: TCP
|
||||
```
|
||||
yaml에서 **nodePort**를 **지정하지 않으면**(열릴 포트입니다) **30000–32767 범위의 포트가 사용됩니다**.
|
||||
yaml에서 **nodePort**를 **지정하지 않으면**(이것이 열릴 포트입니다) **30000–32767 범위의 포트가 사용됩니다**.
|
||||
|
||||
NodePort 또는 LoadBalancer Services를 검토할 때는 traffic-policy 필드도 함께 살펴보세요. 이 필드는 특정 source에서 어떤 nodes와 backends가 유용한지 바꿉니다:
|
||||
```bash
|
||||
kubectl get services --all-namespaces \
|
||||
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
|
||||
```
|
||||
- `externalTrafficPolicy: Local`은 NodePort/LoadBalancer 트래픽에 대해 원래 클라이언트 source IP를 보존하고, 다른 노드의 endpoints로 forwarding하지 않습니다. local ready endpoint가 없는 node는 Service에 다른 곳에 endpoints가 있어도 traffic을 drop할 수 있습니다.
|
||||
- `externalTrafficPolicy: Cluster`는 default이며 어떤 node를 통해서도 forward할 수 있지만, backend logs에는 실제 외부 client IP 대신 node IP가 보일 수 있습니다.
|
||||
- `internalTrafficPolicy: Local`은 cluster 내부 Service traffic을 source node에 local한 endpoints로 제한합니다. 이것은 locality routing이며, authorization boundary가 아닙니다.
|
||||
- `sessionAffinity: ClientIP`는 한 client에서 반복 테스트할 때 같은 backend로 보내게 만들어, 수동 점검 중 다른 ready endpoints를 숨길 수 있습니다.
|
||||
- `trafficDistribution`과 EndpointSlice topology hints는 새로운 clusters에서 같은 zone 또는 같은 node의 endpoints를 선호할 수 있습니다; 이를 hard security policy가 아니라 routing preference로 취급하세요.
|
||||
|
||||
### LoadBalancer
|
||||
|
||||
**cloud provider의 load balancer를 사용하여** Service를 외부에 노출합니다. GKE에서는 [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/)가 생성되며, 이는 모든 트래픽을 service로 전달하는 단일 IP address를 제공합니다. AWS에서는 Load Balancer가 실행됩니다.
|
||||
cloud provider의 load balancer를 **사용하여** Service를 외부에 노출합니다. GKE에서는 [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/)가 생성되며, 하나의 IP address를 제공하고 모든 traffic을 service로 forwarding합니다. AWS에서는 Load Balancer가 실행됩니다.
|
||||
|
||||
노출된 service마다 LoadBalancer 비용을 지불해야 하므로, 비용이 많이 들 수 있습니다.
|
||||
노출된 service마다 LoadBalancer 비용을 지불해야 하므로, 비쌀 수 있습니다.
|
||||
|
||||
모든 LoadBalancers 나열:
|
||||
```bash
|
||||
@@ -96,15 +107,15 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
|
||||
### External IPs
|
||||
|
||||
> [!TIP]
|
||||
> External IPs는 Load Balancers 타입의 services에 의해 노출되며, 일반적으로 external Cloud Provider Load Balancer가 사용될 때 사용됩니다.
|
||||
> External IPs are exposed by services of type Load Balancers and they are generally used when an external Cloud Provider Load Balancer is being used.
|
||||
>
|
||||
> 찾으려면 `EXTERNAL-IP` 필드에 값이 있는 load balancers를 확인하세요.
|
||||
> For finding them, check for load balancers with values in the `EXTERNAL-IP` field.
|
||||
|
||||
**external IP**를 **destination IP**로 하여 cluster로 들어오는 traffic은 Service port에서 **Service endpoints 중 하나로 routed**됩니다. `externalIPs`는 Kubernetes가 관리하지 않으며 cluster administrator의 책임입니다.
|
||||
**external IP**로 (**destination IP**로) 클러스터로 들어오는 트래픽은 Service port에서 **Service endpoints 중 하나로 라우팅**됩니다. `externalIPs`는 Kubernetes가 관리하지 않으며 클러스터 관리자의 책임입니다.
|
||||
|
||||
`externalIPs`는 민감한 route-control 필드입니다. 이 값을 설정할 수 있는 user는 주변 network가 해당 IP를 cluster로 route하는 경우, Service owner가 통제해서는 안 되는 IP address에 대한 traffic을 자기 쪽으로 claim할 수 있기 때문입니다. Kubernetes는 v1.36에서 Service `externalIPs`의 deprecation과 제거 계획을 발표했으므로, 가능한 경우 LoadBalancer integrations 또는 Gateway API 같은 controller-owned exposure mechanisms를 사용하는 것이 좋습니다. 또한 이 필드가 남아 있는 동안에는 이를 carefully restrict/admit 해야 합니다.
|
||||
`externalIPs`는 민감한 route-control 필드입니다. 주변 네트워크가 해당 IP를 클러스터로 라우팅하는 경우, 이를 설정할 수 있는 사용자가 Service 소유자가 제어해서는 안 되는 IP address의 트래픽을 자신이 가져갈 수 있기 때문입니다. Kubernetes는 v1.36에서 Service `externalIPs`의 deprecation과 제거 계획을 발표했으므로, 가능한 경우 LoadBalancer integrations 또는 Gateway API 같은 controller-owned exposure mechanisms를 선호하고, 이 필드가 아직 존재하는 동안에는 주의해서 restrict/admit 하십시오.
|
||||
|
||||
Service spec에서 `externalIPs`는 모든 `ServiceTypes`와 함께 지정할 수 있습니다. 아래 예시에서 "`my-service`"는 클라이언트가 "`80.11.12.10:80`" (`externalIP:port`)로 접근할 수 있습니다.
|
||||
Service spec에서 `externalIPs`는 모든 `ServiceTypes`와 함께 지정할 수 있습니다. 아래 예제에서 "`my-service`"는 "`80.11.12.10:80`" (`externalIP:port`)의 clients가 접근할 수 있습니다.
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
@@ -123,7 +134,7 @@ externalIPs:
|
||||
```
|
||||
### ExternalName
|
||||
|
||||
[**문서에서:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) ExternalName 유형의 Services는 일반적인 selector인 `my-service`나 `cassandra`가 아니라, **Service를 DNS name에 매핑**합니다. 이 Services는 `spec.externalName` 매개변수로 지정합니다.
|
||||
[**문서에서:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) ExternalName 타입의 Services는 일반적인 selector인 `my-service`나 `cassandra`가 아니라, **Service를 DNS 이름에 매핑**합니다. 이러한 Services는 `spec.externalName` 파라미터로 지정합니다.
|
||||
|
||||
예를 들어, 이 Service 정의는 `prod` namespace의 `my-service` Service를 `my.database.example.com`에 매핑합니다:
|
||||
```yaml
|
||||
@@ -136,7 +147,7 @@ spec:
|
||||
type: ExternalName
|
||||
externalName: my.database.example.com
|
||||
```
|
||||
호스트 `my-service.prod.svc.cluster.local`를 조회하면, cluster DNS Service는 값이 `my.database.example.com`인 `CNAME` 레코드를 반환합니다. `my-service`에 접근하는 방식은 다른 Services와 같지만, 중요한 차이점은 **redirection이 proxying이나 forwarding이 아니라 DNS level에서 발생한다는 것**입니다.
|
||||
호스트 `my-service.prod.svc.cluster.local`을 조회할 때, cluster DNS Service는 값이 `my.database.example.com`인 `CNAME` 레코드를 반환합니다. `my-service`에 접근하는 것은 다른 Services와 같은 방식으로 동작하지만, 중요한 차이점은 **redirection이 proxying이나 forwarding이 아니라 DNS level에서 발생한다**는 것입니다.
|
||||
|
||||
모든 ExternalNames를 나열하세요:
|
||||
```bash
|
||||
@@ -144,24 +155,24 @@ kubectl get services --all-namespaces | grep ExternalName
|
||||
```
|
||||
### EndpointSlices
|
||||
|
||||
EndpointSlices는 Service가 현재 라우팅하는 구체적인 백엔드 주소와 포트를 보여준다. Service에 selector가 없을 때, labels만으로 트래픽 경로를 설명할 수 없을 때, 또는 일부 백엔드만 ready 상태일 때 특히 유용하다.
|
||||
EndpointSlices는 Service가 현재 라우팅하는 구체적인 backend 주소와 포트를 보여줍니다. Service에 selector가 없을 때, labels만으로 traffic path를 설명할 수 없을 때, 또는 일부 backend만 ready 상태일 때 특히 유용합니다.
|
||||
|
||||
Service와 연결된 EndpointSlices를 나열한다:
|
||||
Services와 연결된 EndpointSlices를 나열합니다:
|
||||
```bash
|
||||
kubectl get endpointslices --all-namespaces
|
||||
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> -o yaml
|
||||
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
|
||||
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
|
||||
```
|
||||
노출을 검토할 때는 Service selector와 EndpointSlice `targetRef`, endpoint addresses, readiness conditions, 그리고 ports를 비교하세요. selector가 없는 Service는 수동으로 관리되는 EndpointSlices와 함께 사용될 수 있으며, 트래픽을 non-Pod 또는 예상치 못한 대상로 라우팅할 수 있습니다.
|
||||
노출을 검토할 때는 Service selector와 EndpointSlice의 `targetRef`, endpoint addresses, readiness conditions, 그리고 ports를 비교하세요. selectorless Service는 수동으로 관리되는 EndpointSlices와 함께 사용될 수 있으며, traffic을 non-Pod 또는 예상치 못한 destination으로 라우팅할 수 있습니다.
|
||||
|
||||
### Ingress
|
||||
|
||||
위의 모든 예시와 달리, **Ingress는 service의 한 유형이 아닙니다**. 대신 **여러 services 앞에 위치하며 클러스터로 들어오는 “smart router”** 또는 entrypoint 역할을 합니다.
|
||||
위의 모든 예와 달리, **Ingress는 service type이 아닙니다**. 대신 **여러 services 앞에 위치하며 클러스터로 들어오는 “smart router”** 또는 entrypoint 역할을 합니다.
|
||||
|
||||
Ingress로는 다양한 작업을 할 수 있으며, **기능이 서로 다른 여러 종류의 Ingress controllers**가 있습니다.
|
||||
Ingress로 다양한 작업을 할 수 있으며, **서로 다른 capabilities를 가진 여러 종류의 Ingress controllers**가 있습니다.
|
||||
|
||||
기본 GKE ingress controller는 여러분을 위해 [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)를 생성합니다. 이를 통해 path 기반 및 subdomain 기반 routing을 backend services로 할 수 있습니다. 예를 들어, foo.yourdomain.com으로 들어오는 모든 요청을 foo service로 보내고, yourdomain.com/bar/ path 아래의 모든 요청을 bar service로 보낼 수 있습니다.
|
||||
기본 GKE ingress controller는 여러분을 위해 [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)를 생성합니다. 이를 통해 path 기반 및 subdomain 기반 routing을 backend services로 수행할 수 있습니다. 예를 들어, foo.yourdomain.com의 모든 traffic을 foo service로 보내고, yourdomain.com/bar/ path 아래의 모든 traffic을 bar service로 보낼 수 있습니다.
|
||||
|
||||
GKE에서 [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)를 사용하는 Ingress object의 YAML은 다음과 같을 수 있습니다:
|
||||
```yaml
|
||||
@@ -197,19 +208,19 @@ name: bar
|
||||
port:
|
||||
number: 8080
|
||||
```
|
||||
모든 ingress를 나열:
|
||||
모든 ingress를 나열합니다:
|
||||
```bash
|
||||
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
|
||||
```
|
||||
이 경우에는 각각을 하나씩 따로 받아서 더 읽기 쉽게 보는 것이 더 좋습니다:
|
||||
이 경우에는 각 정보를 하나씩 받아서 더 잘 읽는 것이 더 좋습니다:
|
||||
```bash
|
||||
kubectl get ingresses --all-namespaces -o=yaml
|
||||
```
|
||||
### Gateway API
|
||||
|
||||
Gateway API는 Services를 노출하기 위한 더 새로운 Kubernetes API이다. 이는 인프라 소유의 Gateway 객체와 HTTPRoute 같은 애플리케이션 소유의 Route 객체를 분리한다. 이는 delegation에 유용하지만, 노출이 여러 namespace에 걸쳐 분리될 수 있음을 의미하기도 한다.
|
||||
Gateway API는 Services를 노출하기 위한 더 새로운 Kubernetes API입니다. 인프라 소유의 Gateway objects와 HTTPRoute 같은 애플리케이션 소유의 Route objects를 분리합니다. 이는 delegation에 유용하지만, exposure가 namespaces 간에 분리될 수 있다는 뜻이기도 합니다.
|
||||
|
||||
Gateway API exposure objects를 나열한다:
|
||||
Gateway API exposure objects를 나열합니다:
|
||||
```bash
|
||||
kubectl get gatewayclasses
|
||||
kubectl get gateways --all-namespaces
|
||||
@@ -217,13 +228,16 @@ kubectl get httproutes --all-namespaces
|
||||
kubectl get gateway -n <namespace> <gateway-name> -o yaml
|
||||
kubectl get httproute -n <namespace> <route-name> -o yaml
|
||||
```
|
||||
Gateway listener, allowed route namespace, Route `parentRefs`, hostname, filter, backend reference, 그리고 accepted되었는지 같은 status condition을 확인하세요. shared Gateway에 의해 accepted된 Route는 legacy Ingress object가 없어도 backend를 expose할 수 있습니다.
|
||||
Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames, filters, backend references, and status conditions such as whether the route was accepted. A Route that is accepted by a shared Gateway can expose a backend even when no legacy Ingress object exists.
|
||||
|
||||
### References
|
||||
|
||||
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
|
||||
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
|
||||
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
|
||||
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
|
||||
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
|
||||
|
||||
|
||||
@@ -2,62 +2,64 @@
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
**이 페이지의 원저자는** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **입니다(원문은** [**여기**](https://sickrov.github.io)**에서 읽을 수 있습니다)**
|
||||
**이 페이지의 원저자는** [**Jorge**](https://www.linkedin.com/in/jorge-belmonte-a924b616b/) **입니다(원문 게시물은** [**여기**](https://sickrov.github.io)**)**
|
||||
|
||||
## Architecture & Basics
|
||||
|
||||
### Kubernetes는 무엇을 하나요?
|
||||
### What does Kubernetes do?
|
||||
|
||||
- container/s를 container engine에서 실행할 수 있게 해줍니다.
|
||||
- Schedule은 containers를 효율적으로 배치할 수 있게 해줍니다.
|
||||
- container engine에서 container/s 실행을 허용합니다.
|
||||
- Schedule는 containers를 효율적으로 배치하도록 합니다.
|
||||
- containers를 살아 있게 유지합니다.
|
||||
- container communications를 가능하게 합니다.
|
||||
- deployment techniques를 가능하게 합니다.
|
||||
- volumes of information을 처리합니다.
|
||||
- container communications를 허용합니다.
|
||||
- deployment techniques를 허용합니다.
|
||||
- information volume을 처리합니다.
|
||||
|
||||
### Architecture
|
||||
|
||||

|
||||
|
||||
- **Node**: pod 또는 pods가 있는 operating system.
|
||||
- **Pod**: container 또는 여러 containers를 감싸는 Wrapper. pod는 하나의 application만 포함해야 한다(그래서 보통 pod는 container 1개만 실행함). pod는 kubernetes가 실행 중인 container technology를 추상화하는 방식이다.
|
||||
- **Service**: 각 pod는 node의 internal range에서 1개의 내부 **IP address**를 가진다. 하지만 service를 통해 노출될 수도 있다. **service도 IP address를 가지며**, 목적은 pod들 간의 communication을 유지하는 것이다. 그래서 하나가 죽어도 **새 대체본**(다른 internal IP를 가짐)이 **service의 같은 IP로** 접근 가능하게 **노출**된다. internal 또는 external로 설정할 수 있다. service는 또한 **2개의 pods가 같은 service에 연결되면 load balancer**처럼 동작한다.\
|
||||
**service**가 **생성**되면 `kubectl get endpoints`를 실행해 각 service의 endpoints를 확인할 수 있다
|
||||
- **Kubelet**: 주요 node agent. node와 kubectl 사이의 communication을 확립하는 component이며, (API server를 통해) pod만 실행할 수 있다. kubelet은 Kubernetes가 생성하지 않은 containers는 관리하지 않는다.
|
||||
- **Kube-proxy**: apiserver와 node 사이의 communications(services)를 담당하는 service이다. 기본은 nodes용 IPtables이다. 숙련된 사용자라면 다른 vendor의 다른 kube-proxies를 설치할 수도 있다.
|
||||
- **Sidecar container**: main container와 함께 pod에서 실행되어야 하는 containers이다. 이 sidecar pattern은 기존 containers를 변경하지 않고도 그 기능을 확장하고 강화한다. 요즘 우리는 container technology를 사용해 application이 어디서든 실행되도록 모든 dependencies를 감싼다. container는 한 가지 일만 하고 그 일을 매우 잘한다.
|
||||
- **Pod**: container 또는 여러 containers를 감싸는 Wrapper. 하나의 pod는 하나의 application만 포함해야 합니다(그래서 보통 pod는 container 1개만 실행합니다). pod는 kubernetes가 실행 중인 container technology를 추상화하는 방식입니다.
|
||||
- **Service**: 각 pod는 node의 internal range에서 1개의 internal **IP address**를 가집니다. 하지만 service를 통해 노출할 수도 있습니다. **service도 IP address를 가지며**, 목적은 pod 간 통신을 유지하는 것입니다. 그래서 하나가 죽어도 **새 대체 pod**(다른 internal IP 사용)가 **service의 동일한 IP**로 계속 접근 가능하게 됩니다. internal 또는 external로 설정할 수 있습니다. service는 또한 **2개의 pod가 같은 service에 연결될 때 load balancer**처럼 동작합니다.\
|
||||
**service**가 **생성되면** `kubectl get endpoints`를 실행해 각 service의 endpoints를 찾을 수 있습니다
|
||||
- **Kubelet**: 주요 node agent. node와 kubectl 사이의 통신을 설정하는 component이며, pod만 실행할 수 있습니다(API server를 통해). kubelet은 Kubernetes가 생성하지 않은 containers는 관리하지 않습니다.
|
||||
- **Kube-proxy**: apiserver와 node 사이의 communications(services)를 담당하는 service입니다. 기본은 nodes용 IPtables입니다. 숙련된 사용자는 다른 vendor의 다른 kube-proxies를 설치할 수도 있습니다.
|
||||
- **Sidecar container**: main container와 함께 pod에서 실행되어야 하는 containers입니다. 이 sidecar pattern은 기존 containers를 변경하지 않고도 그 기능을 확장하고 향상합니다. 오늘날 우리는 container technology를 사용해 application이 어디서든 실행되도록 필요한 dependencies를 모두 묶는다는 것을 압니다. container는 한 가지만 하고 그 일을 매우 잘합니다.
|
||||
- **Master process:**
|
||||
- **Api Server:** 사용자와 pods가 master process와 communication하기 위해 사용하는 방식이다. 인증된 요청만 허용되어야 한다.
|
||||
- **Scheduler**: Scheduling은 Pods가 Nodes에 매칭되도록 해서 Kubelet이 실행할 수 있게 하는 것이다. 어떤 node에 더 많은 available resources가 있는지 판단해 새 pod를 그쪽에 배치할 만큼의 intelligence를 갖고 있다. scheduler는 새 pods를 시작하지는 않고, node 내부에서 실행 중인 Kubelet process와 communication할 뿐이며, 그 Kubelet이 새 pod를 실행한다는 점에 주의하라.
|
||||
- **Kube Controller manager**: replica sets나 deployments 같은 resources를 확인해 예를 들어 올바른 수의 pods나 nodes가 실행 중인지 검사한다. pod가 하나 없으면 scheduler와 communication하여 새 pod를 시작한다. replication, tokens, account services를 API에 대해 제어한다.
|
||||
- **etcd**: Data storage, persistent, consistent, and distributed. Kubernetes’s database이자 cluster의 complete state를 보관하는 key-value storage이다(모든 변경이 여기에 기록된다). Scheduler나 Controller manager 같은 components는 nodes의 available resources, 실행 중인 pods 수 등 어떤 changes가 발생했는지 알기 위해 이 data에 의존한다.
|
||||
- **Cloud controller manager**: AWS나 OpenStack 같은 경우의 flow controls와 applications을 위한 specific controller이다.
|
||||
- **Api Server:** 사용자가 master process와, 그리고 pods가 통신하는 방식입니다. 인증된 request만 허용해야 합니다.
|
||||
- **Scheduler**: Scheduling은 Pods가 Nodes에 매칭되도록 하여 Kubelet이 이를 실행할 수 있게 보장하는 것입니다. 어떤 node에 더 많은 available resources가 있는지 판단해 새 pod를 그곳에 할당할 만큼의 지능이 있습니다. scheduler는 새 pods를 시작하지 않으며, node 내부에서 실행 중인 Kubelet process와 통신할 뿐입니다. 이 Kubelet이 새 pod를 실행합니다.
|
||||
- **Kube Controller manager**: replica sets나 deployments 같은 resources를 확인해, 예를 들어 올바른 수의 pods 또는 nodes가 실행 중인지 점검합니다. pod가 없으면 scheduler와 통신해 새 pod를 시작합니다. replication, tokens, 그리고 account services를 API에 대해 제어합니다.
|
||||
- **etcd**: data storage, persistent, consistent, and distributed. Kubernetes의 database이자 cluster의 complete state를 저장하는 key-value storage입니다(모든 변경 사항이 여기에 기록됩니다). Scheduler나 Controller manager 같은 components는 어떤 변경이 발생했는지(노드의 available resourced, 실행 중인 pods 수...) 알기 위해 이 date에 의존합니다.
|
||||
- **Cloud controller manager**: AWS나 OpenStack 같은 환경에서 flow controls와 applications을 위한 특정 controller입니다.
|
||||
|
||||
여러 nodes(여러 pods 실행)가 있을 수 있는 것처럼, Api server 접근이 load balanced되고 etcd가 synchronized된 여러 master processes도 있을 수 있다.
|
||||
여러 개의 nodes(여러 pods 실행 가능)가 있을 수 있으므로, Api server 접근이 load balanced되고 etcd가 synchronized된 여러 master processes도 있을 수 있다는 점에 유의하세요.
|
||||
|
||||
**Volumes:**
|
||||
|
||||
pod가 pod가 사라져도 없어지면 안 되는 data를 생성한다면, physical volume에 저장해야 한다. **Kubernetes allow to attach a volume to a pod to persist the data**. volume은 local machine 또는 **remote storage**에 있을 수 있다. 서로 다른 physical nodes에서 pods를 실행한다면 모든 pods가 접근할 수 있도록 remote storage를 사용해야 한다.
|
||||
pod가 사라져도 없어지면 안 되는 데이터를 생성하는 경우, 이를 physical volume에 저장해야 합니다. **Kubernetes는 data를 영속화하기 위해 pod에 volume을 연결할 수 있게 합니다**. volume은 local machine 또는 **remote storage**에 있을 수 있습니다. 서로 다른 physical nodes에서 pods를 실행하는 경우, 모든 pods가 접근할 수 있도록 remote storage를 사용해야 합니다.
|
||||
|
||||
Kubernetes는 최근 버전에서 **image volumes**도 지원합니다. `image` volume은 OCI image 또는 artifact를 Pod 내부의 **read-only** filesystem source로 마운트하며, `volumes[].image.reference` 및 `volumes[].image.pullPolicy` 같은 fields를 사용합니다. kubelet은 container images에 사용되는 것과 같은 credential sources를 사용해 artifact를 가져오며, 여기에는 node credentials, Pod `imagePullSecrets`, 그리고 ServiceAccount `imagePullSecrets`가 포함됩니다. security review에서는 image volumes를 runtime inputs이자 supply-chain dependencies로 취급하세요: reference가 digest로 고정되어 있는지, 어떤 registry credentials가 이를 가져올 수 있는지, 어디에 마운트되는지, 그리고 `subPath`가 보이는 directory를 제한하는지 확인하세요.
|
||||
|
||||
**Other configurations:**
|
||||
|
||||
- **ConfigMap**: 서비스에 접근할 **URLs**를 설정할 수 있다. pod는 여기서 data를 받아 나머지 services(pods)와 어떻게 communication할지 알게 된다. credentials를 저장하기에 권장되는 위치는 아니라는 점에 주의하라!
|
||||
- **Secret**: password, API keys... 같은 secret data를 B64로 인코딩해 **store**하는 곳이다. pod는 필요한 credentials를 사용하기 위해 이 data에 접근할 수 있다.
|
||||
- **Deployments**: kubernetes가 실행할 components를 지정하는 곳이다. 사용자는 보통 pods와 직접 작업하지 않으며, pods는 **ReplicaSets**(같은 pods의 복제 수)로 추상화되고, 이 ReplicaSets는 deployments를 통해 실행된다. deployments는 **stateless** applications용이라는 점에 주의하라. deployment의 최소 설정은 name과 실행할 image이다.
|
||||
- **StatefulSet**: **databases**처럼 **같은 storage에 접근해야 하는** applications를 위해 특별히 만든 component이다.
|
||||
- **Ingress**: application을 **URL로 public하게 노출**하기 위한 configuration이다. external services를 사용해서도 할 수 있지만, application을 노출하는 올바른 방법은 이것이다.
|
||||
- Ingress를 구현하면 **Ingress Controllers**를 생성해야 한다. Ingress Controller는 요청을 받고 검사하며 services로 load balance하는 endpoint 역할을 하는 **pod**이다. ingress controller는 **구성된 ingress rules에 따라 요청을 보낸다**. ingress rules는 서로 다른 paths나 subdomains를 서로 다른 internal kubernetes services로 보낼 수 있다.
|
||||
- 더 나은 security practice는 cloud load balancer나 proxy server를 entrypoint로 사용해 Kubernetes cluster의 어떤 부분도 exposed되지 않게 하는 것이다.
|
||||
- 어떤 ingress rule에도 맞지 않는 request가 수신되면 ingress controller는 그것을 "**Default backend**"로 보낸다. `describe`를 사용해 ingress controller를 확인하면 이 parameter의 address를 얻을 수 있다.
|
||||
- **ConfigMap**: services에 접근하기 위한 **URLs**를 설정할 수 있습니다. pod는 나머지 services(pods)와 어떻게 통신할지 알기 위해 여기서 data를 얻습니다. credentials를 저장하기에 권장되는 위치가 아니라는 점에 유의하세요!
|
||||
- **Secret**: passwords, API keys... 같은 secret data를 B64로 인코딩해 **저장**하는 곳입니다. pod는 필요한 credentials를 사용하기 위해 이 data에 접근할 수 있습니다.
|
||||
- **Deployments**: kubernetes가 실행해야 할 components를 지정하는 곳입니다. 사용자는 보통 pods를 직접 다루지 않으며, pods는 **ReplicaSets**(동일한 pods의 복제 수)으로 추상화되고, deployments를 통해 실행됩니다. deployments는 **stateless** applications용입니다. deployment의 최소 구성은 name과 실행할 image입니다.
|
||||
- **StatefulSet**: 이 component는 **databases**처럼 **같은 storage에 접근해야 하는** applications를 위해 특별히 만들어졌습니다.
|
||||
- **Ingress**: application을 **URL로 public하게 노출**하기 위한 configuration입니다. external services를 사용해서도 할 수 있지만, application을 노출하는 올바른 방법은 이것입니다.
|
||||
- Ingress를 구현하면 **Ingress Controllers**를 만들어야 합니다. Ingress Controller는 요청을 받아 검사하고 services로 load balance하는 endpoint가 되는 **pod**입니다. ingress controller는 **설정된 ingress rules에 따라 request를 보냅니다**. ingress rules는 서로 다른 internal kubernetes services의 different paths 또는 subdomains을 가리킬 수 있습니다.
|
||||
- 더 나은 security practice는 Kubernetes cluster의 어떤 부분도 exposed되지 않도록 cloud load balancer나 proxy server를 entrypoint로 사용하는 것입니다.
|
||||
- 어떤 ingress rule에도 맞지 않는 request가 수신되면 ingress controller는 이를 "**Default backend**"로 보냅니다. 이 parameter의 address를 얻으려면 ingress controller를 `describe`할 수 있습니다.
|
||||
- `minikube addons enable ingress`
|
||||
|
||||
### PKI infrastructure - Certificate Authority CA:
|
||||
|
||||

|
||||
|
||||
- CA is cluster 내부의 모든 certificates에 대한 trusted root이다.
|
||||
- components가 서로를 validate할 수 있게 해준다.
|
||||
- 모든 cluster certificates는 CA에 의해 signed된다.
|
||||
- CA is the trusted root for all certificates inside the cluster.
|
||||
- components가 서로를 validate할 수 있게 합니다.
|
||||
- 모든 cluster certificates는 CA에 의해 서명됩니다.
|
||||
- ETCd has its own certificate.
|
||||
- types:
|
||||
- apiserver cert.
|
||||
@@ -68,7 +70,7 @@ pod가 pod가 사라져도 없어지면 안 되는 data를 생성한다면, phys
|
||||
|
||||
### Minikube
|
||||
|
||||
**Minikube**는 전체 kubernetes environment를 배포하지 않고도 kubernetes에서 몇 가지 **quick tests**를 수행하는 데 사용할 수 있다. 이는 **master와 node processes를 한 대의 machine에서** 실행한다. Minikube는 virtualbox를 사용해 node를 실행한다. 설치 방법은 [**여기**](https://minikube.sigs.k8s.io/docs/start/)를 참고하라.
|
||||
**Minikube**는 전체 kubernetes environment를 배포하지 않고도 kubernetes에서 몇 가지 **quick tests**를 수행하는 데 사용할 수 있습니다. **master와 node processes를 한 대의 machine에서 실행**합니다. Minikube는 virtualbox를 사용해 node를 실행합니다. 설치 방법은 [**여기**](https://minikube.sigs.k8s.io/docs/start/)를 보세요.
|
||||
```
|
||||
$ minikube start
|
||||
😄 minikube v1.19.0 on Ubuntu 20.04
|
||||
@@ -105,7 +107,7 @@ $ minikube delete
|
||||
```
|
||||
### Kubectl Basics
|
||||
|
||||
**`Kubectl`**는 kubernetes 클러스터를 위한 command line tool입니다. master process의 Api server와 통신하여 kubernetes에서 작업을 수행하거나 데이터를 요청합니다.
|
||||
**`Kubectl`**는 kubernetes 클러스터를 위한 command line tool입니다. 이는 master process의 Api server와 통신하여 kubernetes에서 작업을 수행하거나 데이터를 요청합니다.
|
||||
```bash
|
||||
kubectl version #Get client and server version
|
||||
kubectl get pod
|
||||
@@ -138,7 +140,7 @@ kubectl apply -f deployment.yml
|
||||
```
|
||||
### Minikube Dashboard
|
||||
|
||||
dashboard를 사용하면 minikube가 실행 중인 내용을 더 쉽게 볼 수 있으며, 접근할 URL은 다음에서 찾을 수 있습니다:
|
||||
dashboard를 사용하면 minikube에서 무엇이 실행 중인지 더 쉽게 볼 수 있습니다. 접근할 URL은 다음에서 찾을 수 있습니다:
|
||||
```
|
||||
minikube dashboard --url
|
||||
|
||||
@@ -154,11 +156,11 @@ http://127.0.0.1:50034/api/v1/namespaces/kubernetes-dashboard/services/http:kube
|
||||
### YAML configuration files examples
|
||||
|
||||
Each configuration file has 3 parts: **metadata**, **specification** (what need to be launch), **status** (desired state).\
|
||||
deployment configuration file의 specification 내부에서 실행할 image를 정의하는 새로운 configuration structure로 정의된 template을 찾을 수 있습니다:
|
||||
deployment configuration file의 specification 안에는 실행할 image를 정의하는 새로운 configuration 구조와 함께 정의된 template를 찾을 수 있습니다:
|
||||
|
||||
**Example of Deployment + Service declared in the same configuration file (from** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
|
||||
**같은 configuration file에 선언된 Deployment + Service 예시 (** [**here**](https://gitlab.com/nanuchi/youtube-tutorial-series/-/blob/master/demo-kubernetes-components/mongo.yaml)**)**
|
||||
|
||||
Service는 보통 하나의 deployment와 연결되므로, 같은 configuration file에 둘 다 선언할 수 있습니다(이 config에 선언된 service는 내부에서만 접근 가능합니다):
|
||||
service는 보통 하나의 deployment와 연관되므로, 같은 configuration file에 둘 다 선언하는 것이 가능합니다 (이 config에 선언된 service는 내부에서만 접근 가능합니다):
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -207,7 +209,7 @@ targetPort: 27017
|
||||
```
|
||||
**외부 서비스 config의 예시**
|
||||
|
||||
이 service는 외부에서 접근 가능할 것입니다(`nodePort` 및 `type: LoadBlancer` 속성을 확인하세요):
|
||||
이 service는 외부에서 접근 가능할 것입니다(`nodePort` 및 `type: LoadBlancer` attributes를 확인):
|
||||
```yaml
|
||||
---
|
||||
apiVersion: v1
|
||||
@@ -225,11 +227,11 @@ targetPort: 8081
|
||||
nodePort: 30000
|
||||
```
|
||||
> [!NOTE]
|
||||
> 이는 테스트에 유용하지만, production에서는 internal services만 두고 application을 expose하기 위해 Ingress를 사용해야 합니다.
|
||||
> 이는 testing에 유용하지만 production에서는 internal services만 두고 application을 expose하기 위해 Ingress를 사용해야 합니다.
|
||||
|
||||
**Example of Ingress config file**
|
||||
|
||||
이것은 `http://dashboard.com`에서 application을 expose합니다.
|
||||
이렇게 하면 application이 `http://dashboard.com`에서 expose됩니다.
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
@@ -245,9 +247,9 @@ paths:
|
||||
serviceName: kubernetes-dashboard
|
||||
servicePort: 80
|
||||
```
|
||||
**비밀 config file의 예시**
|
||||
**Secrets config file의 예**
|
||||
|
||||
password가 B64로 encoded된 것을 보세요(이는 secure하지 않습니다!)
|
||||
password가 B64로 인코딩되어 있는 것을 주목하세요(이는 secure하지 않습니다!)
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -260,7 +262,7 @@ mongo-root-password: cGFzc3dvcmQ=
|
||||
```
|
||||
**ConfigMap 예시**
|
||||
|
||||
**ConfigMap**은 pod에 제공되는 설정으로, pod가 다른 서비스의 위치를 찾고 접근하는 방법을 알 수 있게 합니다. 이 경우 각 pod는 `mongodb-service`라는 이름이 통신할 수 있는 pod의 주소라는 것을 알게 됩니다(이 pod는 mongodb를 실행합니다):
|
||||
**ConfigMap**은 pods에 제공되는 configuration으로, 다른 services를 어떻게 찾아서 접근해야 하는지 알 수 있게 해줍니다. 이 경우 각 pod는 `mongodb-service`라는 이름이 자신들이 통신할 수 있는 pod의 address라는 것을 알게 됩니다. (이 pod는 mongodb를 실행할 것입니다):
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -269,7 +271,7 @@ name: mongodb-configmap
|
||||
data:
|
||||
database_url: mongodb-service
|
||||
```
|
||||
그런 다음, **deployment config** 내부에서 이 주소를 다음과 같은 방식으로 지정할 수 있으며, 그러면 pod의 env에 로드됩니다:
|
||||
그런 다음, **deployment config** 내부에서 이 주소를 다음과 같이 지정할 수 있어, pod의 env 안에 로드되도록 할 수 있다:
|
||||
```yaml
|
||||
[...]
|
||||
spec:
|
||||
@@ -290,18 +292,18 @@ name: mongodb-configmap
|
||||
key: database_url
|
||||
[...]
|
||||
```
|
||||
**볼륨 구성 예시**
|
||||
**volume config 예시**
|
||||
|
||||
[https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes](https://gitlab.com/nanuchi/youtube-tutorial-series/-/tree/master/kubernetes-volumes)에서 다양한 storage configuration yaml 파일 예시를 찾을 수 있습니다.\
|
||||
**volumes는 namespaces 안에 있지 않습니다**
|
||||
|
||||
### Namespaces
|
||||
|
||||
Kubernetes는 동일한 physical cluster를 기반으로 하는 **여러 virtual clusters**를 지원합니다. 이러한 virtual clusters를 **namespaces**라고 합니다. 이는 여러 팀이나 프로젝트에 걸쳐 많은 사용자가 있는 환경에서 사용하도록 되어 있습니다. 몇 명에서 수십 명 정도의 사용자가 있는 cluster에서는 namespaces를 만들거나 전혀 생각할 필요가 없습니다. kubernetes에 배포된 애플리케이션의 각 부분을 더 잘 제어하고 정리하기 위해서만 namespaces를 사용하기 시작하면 됩니다.
|
||||
Kubernetes는 동일한 physical cluster 위에 구축된 **여러 virtual clusters**를 지원합니다. 이러한 virtual clusters를 **namespaces**라고 합니다. 이는 여러 팀이나 프로젝트에 걸쳐 많은 사용자가 있는 환경에서 사용하도록 의도되었습니다. 몇 명에서 수십 명 정도의 사용자가 있는 cluster라면, namespaces를 만들거나 따로 생각할 필요가 없습니다. kubernetes에 배포된 application의 각 부분을 더 잘 control하고 organization하기 위해서만 namespaces를 사용하기 시작하면 됩니다.
|
||||
|
||||
Namespaces는 names에 대한 scope를 제공합니다. resource의 이름은 namespace 내에서만 unique하면 되며, namespaces 전체에서 unique할 필요는 없습니다. Namespaces는 서로 안에 중첩될 수 없으며, **각** Kubernetes **resource**는 **하나의** **namespace**에만 있을 수 있습니다.
|
||||
Namespaces는 names에 대한 scope를 제공합니다. resource의 name은 namespace 내에서는 unique해야 하지만, namespaces 간에는 unique할 필요가 없습니다. Namespaces는 서로 안에 중첩될 수 없으며 **각** Kubernetes **resource**는 **하나의** **namespace**에만 **존재**할 수 있습니다.
|
||||
|
||||
minikube를 사용한다면 기본적으로 4개의 namespaces가 있습니다:
|
||||
minikube를 사용 중이라면 기본적으로 4개의 namespaces가 있습니다:
|
||||
```
|
||||
kubectl get namespace
|
||||
NAME STATUS AGE
|
||||
@@ -310,7 +312,7 @@ kube-node-lease Active 1d
|
||||
kube-public Active 1d
|
||||
kube-system Active 1d
|
||||
```
|
||||
- **kube-system**: 사용자가 사용하도록 만들어진 것이 아니며 건드리면 안 됩니다. master와 kubectl 프로세스를 위한 것입니다.
|
||||
- **kube-system**: 사용자를 위한 것이 아니며 사용해서도 안 됩니다. master와 kubectl 프로세스를 위한 것입니다.
|
||||
- **kube-public**: 공개적으로 접근 가능한 데이터. cluster 정보를 포함하는 configmap을 포함합니다.
|
||||
- **kube-node-lease**: node의 가용성을 결정합니다.
|
||||
- **default**: 사용자가 resources를 생성할 때 사용할 namespace입니다.
|
||||
@@ -319,30 +321,30 @@ kube-system Active 1d
|
||||
kubectl create namespace my-namespace
|
||||
```
|
||||
> [!NOTE]
|
||||
> 대부분의 Kubernetes 리소스(예: pods, services, replication controllers, 등)는 일부 namespace에 속합니다. 하지만 namespace resources와 nodes, persistenVolumes 같은 low-level resources는 namespace에 속하지 않습니다. 어떤 Kubernetes resources가 namespace에 있고 없는지 확인하려면:
|
||||
> 대부분의 Kubernetes 리소스(예: pods, services, replication controllers 및 기타)는 일부 namespaces에 있습니다. 그러나 namespace resources와 nodes, persistenVolumes 같은 low-level resources는 namespace 안에 있지 않습니다. 어떤 Kubernetes resources가 namespace 안에 있고 없는지 확인하려면:
|
||||
>
|
||||
> ```bash
|
||||
> kubectl api-resources --namespaced=true #In a namespace
|
||||
> kubectl api-resources --namespaced=false #Not in a namespace
|
||||
> ```
|
||||
|
||||
해당 context에서 이후의 모든 kubectl commands를 위해 namespace를 저장할 수 있습니다.
|
||||
그 context에서 이후의 모든 kubectl commands에 대해 namespace를 저장할 수 있습니다.
|
||||
```bash
|
||||
kubectl config set-context --current --namespace=<insert-namespace-name-here>
|
||||
```
|
||||
### Helm
|
||||
|
||||
Helm은 Kubernetes용 **package manager**입니다. YAML 파일을 패키징해 public 및 private repository에 배포할 수 있게 해줍니다. 이러한 패키지는 **Helm Charts**라고 불립니다.
|
||||
Helm은 Kubernetes용 **package manager**입니다. YAML 파일을 패키징하고 public 및 private repository에서 배포할 수 있게 해줍니다. 이러한 패키지는 **Helm Charts**라고 불립니다.
|
||||
```
|
||||
helm search <keyword>
|
||||
```
|
||||
Helm은 변수로 config 파일을 생성할 수 있게 해주는 template engine이기도 합니다:
|
||||
Helm은 변수로 config files를 생성할 수 있게 해주는 template engine이기도 합니다:
|
||||
|
||||
## Kubernetes secrets
|
||||
|
||||
A **Secret**는 **password**, **token**, **key** 같은 민감한 데이터를 **포함하는** object입니다. 이런 정보는 Pod specification이나 image 안에 들어갈 수도 있습니다. Users can create Secrets and the system also creates Secrets. Secret object의 이름은 유효한 **DNS subdomain name**이어야 합니다. 여기서 읽어보세요 [the official documentation](https://kubernetes.io/docs/concepts/configuration/secret/).
|
||||
**Secret**은 password, token, key 같은 **sensitive data**를 **포함하는** object입니다. 이런 정보는 Pod specification이나 image 안에 넣을 수도 있습니다. Users는 Secrets를 만들 수 있고, system도 Secrets를 만듭니다. Secret object의 이름은 유효한 **DNS subdomain name**이어야 합니다. 여기서 공식 문서를 읽어보세요 [the official documentation](https://kubernetes.io/docs/concepts/configuration/secret/).
|
||||
|
||||
Secrets는 다음과 같은 것일 수 있습니다:
|
||||
Secrets에는 다음 같은 것들이 있을 수 있습니다:
|
||||
|
||||
- API, SSH Keys.
|
||||
- OAuth tokens.
|
||||
@@ -364,13 +366,13 @@ Kubernetes에는 여러 종류의 secrets가 있습니다
|
||||
| bootstrap.kubernetes.io/token | bootstrap token data |
|
||||
|
||||
> [!NOTE]
|
||||
> **Opaque type이 기본값이며, 보통 사용자가 정의하는 key-value pair입니다.**
|
||||
> **Opaque type은 기본값이며, users가 정의하는 일반적인 key-value pair입니다.**
|
||||
|
||||
**How secrets works:**
|
||||
**secrets가 작동하는 방식:**
|
||||
|
||||

|
||||
|
||||
다음 configuration file은 `mysecret`이라는 **secret**를 정의하며, `username: YWRtaW4=`와 `password: MWYyZDFlMmU2N2Rm` 두 개의 key-value pair를 포함합니다. 또한 `secretpod`라는 **pod**를 정의하는데, 이 pod는 `mysecret`에 정의된 `username`과 `password`를 **environment variables** `SECRET_USERNAME` \_\_ 그리고 \_\_ `SECRET_PASSWOR`로 노출합니다. 또한 `mysecret` 안의 `username` secret을 `/etc/foo/my-group/my-username` 경로에 `0640` permissions으로 **mount**합니다.
|
||||
다음 configuration file은 `mysecret`이라는 **secret**을 정의하며, `username: YWRtaW4=`과 `password: MWYyZDFlMmU2N2Rm`라는 2개의 key-value pair를 가집니다. 또한 `secretpod`라는 **pod**를 정의하는데, 이 pod는 `mysecret`에 정의된 `username`과 `password`를 **environment variables** `SECRET_USERNAME` \_\_ 및 \_\_ `SECRET_PASSWOR`로 노출합니다. 또한 `mysecret` 안의 `username` secret을 `/etc/foo/my-group/my-username` 경로에 `0640` permissions로 **mount**합니다.
|
||||
```yaml:secretpod.yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -422,25 +424,25 @@ env | grep SECRET && cat /etc/foo/my-group/my-username && echo
|
||||
```
|
||||
### etcd의 Secrets <a href="#discover-secrets-in-etcd" id="discover-secrets-in-etcd"></a>
|
||||
|
||||
**etcd**는 Kubernetes의 백엔드 스토리지로 사용되는 일관되고 고가용성인 **key-value store**로, 모든 클러스터 데이터를 저장합니다. etcd에 저장된 secrets에 접근해봅시다:
|
||||
**etcd**는 Kubernetes의 백업 스토어로 사용되는, 일관되고 고가용성인 **key-value store**로, 모든 cluster data를 저장합니다. 이제 etcd에 저장된 secrets에 접근해 봅시다:
|
||||
```bash
|
||||
cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep etcd
|
||||
```
|
||||
FS에 위치한 certs, keys 및 url’s를 볼 수 있습니다. 이를 얻으면 etcd에 연결할 수 있게 됩니다.
|
||||
FS에 certs, keys and url’s가 위치해 있는 것을 보게 될 것이다. 그것들을 얻으면 etcd에 연결할 수 있게 된다.
|
||||
```bash
|
||||
#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
|
||||
```
|
||||
일단 통신을 확립하면 secrets를 얻을 수 있습니다:
|
||||
통신을 수립하면 secrets를 얻을 수 있습니다:
|
||||
```bash
|
||||
#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에 encryption 추가하기**
|
||||
**ETCD에 encryption 추가**
|
||||
|
||||
기본적으로 모든 secrets는 encryption layer를 적용하지 않으면 etcd 내부에 plain text로 **stored in plain** 되어 있습니다. 다음 예시는 [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)를 기반으로 합니다
|
||||
기본적으로 모든 secrets는 encryption layer를 적용하지 않으면 etcd 내부에 **plain** text로 저장됩니다. 다음 예시는 [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)를 기반으로 합니다.
|
||||
```yaml:encryption.yaml
|
||||
apiVersion: apiserver.config.k8s.io/v1
|
||||
kind: EncryptionConfiguration
|
||||
@@ -454,20 +456,20 @@ keys:
|
||||
secret: cjjPMcWpTPKhAdieVtd+KhG4NN+N6e3NmBPMXJvbfrY= #Any random key
|
||||
- identity: {}
|
||||
```
|
||||
그런 다음, 생성된 config file의 위치를 가리키도록 `kube-apiserver`에 `--encryption-provider-config` flag를 설정해야 합니다. `/etc/kubernetes/manifest/kube-apiserver.yaml`를 수정하고 다음 lines를 추가할 수 있습니다:
|
||||
그 후, 생성된 config 파일의 위치를 가리키도록 `kube-apiserver`에 `--encryption-provider-config` 플래그를 설정해야 합니다. `/etc/kubernetes/manifest/kube-apiserver.yaml`을 수정하고 다음 줄을 추가할 수 있습니다:
|
||||
```yaml
|
||||
containers:
|
||||
- command:
|
||||
- kube-apiserver
|
||||
- --encriyption-provider-config=/etc/kubernetes/etcd/<configFile.yaml>
|
||||
```
|
||||
volumeMounts에서 아래로 스크롤하세요:
|
||||
volumeMounts에서 아래로 스크롤:
|
||||
```yaml
|
||||
- mountPath: /etc/kubernetes/etcd
|
||||
name: etcd
|
||||
readOnly: true
|
||||
```
|
||||
volumeMounts에서 아래로 스크롤하여 hostPath:를 찾으세요:
|
||||
volumeMounts에서 hostPath까지 아래로 스크롤:
|
||||
```yaml
|
||||
- hostPath:
|
||||
path: /etc/kubernetes/etcd
|
||||
@@ -476,7 +478,7 @@ name: etcd
|
||||
```
|
||||
**데이터가 암호화되었는지 확인하기**
|
||||
|
||||
데이터는 etcd에 기록될 때 암호화됩니다. `kube-apiserver`를 재시작한 후 새로 생성되거나 업데이트된 any secret은 저장될 때 암호화되어야 합니다. 확인하려면 `etcdctl` command line program을 사용해 secret의 내용을 가져올 수 있습니다.
|
||||
데이터는 etcd에 기록될 때 암호화됩니다. `kube-apiserver`를 재시작한 뒤, 새로 생성되거나 업데이트된 secret은 저장될 때 암호화되어야 합니다. 이를 확인하려면 `etcdctl` command line program을 사용해 secret의 내용을 가져오면 됩니다.
|
||||
|
||||
1. `default` namespace에 `secret1`라는 새 secret을 생성합니다:
|
||||
|
||||
@@ -484,29 +486,29 @@ name: etcd
|
||||
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
|
||||
```
|
||||
|
||||
2. etcdctl commandline을 사용해 etcd에서 해당 secret을 읽어옵니다:
|
||||
2. etcdctl commandline을 사용해 etcd에서 그 secret을 읽어옵니다:
|
||||
|
||||
`ETCDCTL_API=3 etcdctl get /registry/secrets/default/secret1 [...] | hexdump -C`
|
||||
|
||||
여기서 `[...]`는 etcd server에 연결하기 위한 추가 arguments여야 합니다.
|
||||
|
||||
3. 저장된 secret이 `k8s:enc:aescbc:v1:`로 시작하는지 확인합니다. 이는 `aescbc` provider가 결과 데이터를 encrypted했다는 뜻입니다.
|
||||
4. API를 통해 가져왔을 때 secret이 올바르게 decrypted되는지 확인합니다:
|
||||
3. 저장된 secret이 `k8s:enc:aescbc:v1:`로 시작하는지 확인합니다. 이는 `aescbc` provider가 결과 데이터를 암호화했음을 의미합니다.
|
||||
4. API를 통해 가져올 때 secret이 올바르게 복호화되는지 확인합니다:
|
||||
|
||||
```
|
||||
kubectl describe secret secret1 -n default
|
||||
```
|
||||
|
||||
결과가 `mykey: bXlkYXRh`와 일치해야 합니다. `mydata`는 encoded되어 있으므로, secret을 완전히 decode하려면 [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret)를 확인하세요.
|
||||
는 `mykey: bXlkYXRh`와 일치해야 합니다. `mydata`는 encoded되어 있으므로, secret을 완전히 decode하려면 [decoding a secret](https://kubernetes.io/docs/concepts/configuration/secret#decoding-a-secret)를 확인하세요.
|
||||
|
||||
**secrets는 write 시 암호화되므로, secret을 update하면 해당 내용도 암호화됩니다:**
|
||||
**secret은 write 시 암호화되므로, secret을 update하면 그 내용도 암호화됩니다:**
|
||||
```
|
||||
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
|
||||
```
|
||||
**최종 팁:**
|
||||
**Final tips:**
|
||||
|
||||
- secrets를 FS에 보관하지 말고, 다른 곳에서 가져오세요.
|
||||
- secrets를 더 보호하기 위해 [https://www.vaultproject.io/](https://www.vaultproject.io)를 확인해보세요.
|
||||
- FS에 secrets를 보관하지 말고, 다른 곳에서 가져오세요.
|
||||
- [https://www.vaultproject.io/](https://www.vaultproject.io) 를 확인해서 secrets에 더 많은 보호를 추가하세요.
|
||||
- [https://kubernetes.io/docs/concepts/configuration/secret/#risks](https://kubernetes.io/docs/concepts/configuration/secret/#risks)
|
||||
- [https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/11.2/en/Content/Integrations/Kubernetes_deployApplicationsConjur-k8s-Secrets.htm)
|
||||
|
||||
@@ -520,4 +522,12 @@ https://sickrov.github.io/
|
||||
https://www.youtube.com/watch?v=X48VuDVv0do
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/concepts/storage/volumes/#image
|
||||
{{#endref}}
|
||||
|
||||
{{#ref}}
|
||||
https://kubernetes.io/docs/tasks/configure-pod-container/image-volumes/
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../banners/hacktricks-training.md}}
|
||||
|
||||
+41
-35
@@ -6,79 +6,85 @@
|
||||
|
||||
[**문서에서:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
|
||||
|
||||
Pod의 security context를 지정할 때 여러 속성을 사용할 수 있습니다. 방어적 보안 관점에서는 다음을 고려해야 합니다:
|
||||
Pod의 security context를 지정할 때 여러 속성을 사용할 수 있습니다. 방어적 보안 관점에서 다음을 고려해야 합니다:
|
||||
|
||||
- **runASNonRoot**를 **True**로 설정
|
||||
- **runAsUser**를 구성
|
||||
- 가능하다면 **seLinuxOptions**와 **seccompProfile**을 지정하여 **권한**을 **제한**
|
||||
- **runAsGroup** 및 **supplementaryGroups**를 통해 **privilege** **group** 접근 권한을 **주지 말 것**
|
||||
- **runAsUser** 구성
|
||||
- 가능하다면 **seLinuxOptions**와 **seccompProfile**로 **permissions**를 **제한**하는 것을 고려
|
||||
- **runAsGroup** 및 **supplementaryGroups**를 통해 **privilege** **group** 접근을 **주지 마십시오**
|
||||
|
||||
| Parameter | Description |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>Pod의 <strong>모든 containers</strong>에 적용되는 특수 supplemental group입니다. 일부 volume 유형은 Kubelet이 해당 volume의 <strong>소유권을 Pod 소유로 변경</strong>하도록 허용합니다:<br>1. 소유 GID는 FSGroup이 됩니다<br>2. setgid 비트가 설정됩니다( volume에서 생성된 새 파일은 FSGroup 소유가 됨 )<br>3. permission 비트는 rw-rw----와 OR 됩니다. 설정되지 않으면 Kubelet은 어떤 volume의 소유권과 permissions도 수정하지 않습니다</p> |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>pod의 <strong>모든 containers</strong>에 적용되는 특수한 보조 그룹입니다. 일부 volume 유형은 Kubelet이 해당 volume의 <strong>소유권을 pod 소유로 변경</strong>하도록 허용합니다:<br>1. 소유 GID는 FSGroup이 됩니다<br>2. setgid 비트가 설정됩니다( volume에서 생성된 새 파일은 FSGroup 소유가 됨)<br>3. permission 비트는 rw-rw----와 OR'd 됩니다. 설정되지 않으면 Kubelet은 어떤 volume의 소유권과 permissions도 수정하지 않습니다</p> |
|
||||
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | Pod 내부에 노출되기 전에 **volume의 소유권과 permission을 변경**하는 동작을 정의합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | Pod 내부에 노출되기 전에 volume의 **소유권과 permission을 변경**하는 동작을 정의합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **GID**입니다. 설정되지 않으면 runtime 기본값을 사용합니다. SecurityContext에서도 설정할 수 있습니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container가 non-root 사용자로 실행되어야 함을 나타냅니다. true이면 Kubelet은 runtime에서 image를 검증하여 UID 0(root)으로 실행되지 않는지 확인하고, 그렇다면 container 시작을 실패시킵니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **UID**입니다. 지정하지 않으면 image metadata에 명시된 사용자로 기본 설정됩니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | 모든 containers에 적용될 **SELinux context**입니다. 지정하지 않으면 container runtime이 각 container마다 무작위 SELinux context를 할당합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | 이 Pod의 containers에서 사용할 **seccomp options**입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | container의 primary GID 외에, 각 container에서 실행되는 첫 번째 process에 적용되는 **groups** 목록입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctls는 Pod에 사용되는 **namespaced sysctls 목록**을 보관합니다. 지원되지 않는 sysctls(container runtime 기준)를 가진 Pods는 시작에 실패할 수 있습니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container가 non-root user로 실행되어야 함을 나타냅니다. true이면 Kubelet은 runtime에서 image를 검증하여 UID 0(root)으로 실행되지 않도록 확인하고, 그렇다면 container 시작을 실패시킵니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **UID**입니다. 지정하지 않으면 image 메타데이터에 지정된 user가 기본값이 됩니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | 모든 containers에 적용될 **SELinux context**입니다. 지정하지 않으면 container runtime이 각 container에 대해 무작위 SELinux context를 할당합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | 이 pod의 containers가 사용할 **seccomp options**입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | container의 primary GID에 추가로, 각 container에서 실행되는 첫 번째 process에 적용되는 **groups 목록**입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctls는 pod에 사용되는 **namespaced sysctls 목록**을 보관합니다. (container runtime에서) 지원되지 않는 sysctls가 있는 Pod는 시작에 실패할 수 있습니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | 모든 containers에 적용되는 Windows 전용 설정입니다. 지정하지 않으면 container의 SecurityContext 내 옵션이 사용됩니다. |
|
||||
|
||||
## SecurityContext
|
||||
|
||||
[**문서에서:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
|
||||
|
||||
이 context는 **containers definitions** 내부에 설정됩니다. 방어적 보안 관점에서는 다음을 고려해야 합니다:
|
||||
이 context는 **containers definitions** 안에 설정됩니다. 방어적 보안 관점에서 다음을 고려해야 합니다:
|
||||
|
||||
- **allowPrivilegeEscalation**을 **False**로 설정
|
||||
- 민감한 **capabilities**를 추가하지 말고(그리고 필요 없는 것은 제거)
|
||||
- 민감한 **capabilities**를 추가하지 말고(필요 없는 것은 제거)
|
||||
- **privileged**를 **False**로 설정
|
||||
- 가능하다면 **readOnlyFilesystem**을 **True**로 설정
|
||||
- **runAsNonRoot**를 **True**로 설정하고 **runAsUser**를 설정
|
||||
- 가능하다면 **seLinuxOptions**와 **seccompProfile**을 지정하여 **권한**을 **제한**
|
||||
- **runAsGroup**을 통해 **privilege** **group** 접근 권한을 **주지 말 것.**
|
||||
- **runAsNonRoot**를 **True**로 설정하고 **runAsUser**를 지정
|
||||
- 가능하다면 **seLinuxOptions**와 **seccompProfile**로 **permissions**를 **제한**하는 것을 고려
|
||||
- **runAsGroup**을 통해 **privilege** **group** 접근을 **주지 마십시오.**
|
||||
|
||||
**SecurityContext**와 **PodSecurityContext** 모두에 설정된 속성은, **SecurityContext**에 지정된 값이 **우선**합니다.
|
||||
**SecurityContext와 PodSecurityContext 둘 다**에 설정된 속성은 **SecurityContext**에 지정된 값이 **우선** 적용됩니다.
|
||||
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation**은 process가 부모 process보다 **더 많은 privileges를 획득할 수 있는지**를 제어합니다. 이 bool은 container process에 no_new_privs 플래그를 설정할지 직접 제어합니다. container가 **Privileged**로 실행되거나 **CAP_SYS_ADMIN**을 가지면 AllowPrivilegeEscalation은 항상 true입니다 |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation**은 process가 부모 process보다 **더 많은 privileges를 획득**할 수 있는지 제어합니다. 이 bool은 no_new_privs flag가 container process에 설정되는지를 직접 제어합니다. container가 **Privileged**로 실행되거나 **CAP_SYS_ADMIN**을 가지면 AllowPrivilegeEscalation은 항상 true입니다 |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | containers 실행 시 추가/제거할 **capabilities**입니다. 기본 capabilities 세트가 기본값입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | container를 privileged mode로 실행합니다. privileged containers의 process는 본질적으로 **host의 root와 동등**합니다. 기본값은 false입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount는 containers에 사용할 **proc mount 유형**을 나타냅니다. 기본값은 readonly paths와 masked paths에 container runtime 기본값을 사용하는 DefaultProcMount입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | 이 **container가 read-only root filesystem을 가지는지** 여부입니다. 기본값은 false입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | container를 실행할 때 추가/제거할 **capabilities**입니다. 기본 capabilities 집합이 기본값입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | container를 privileged mode로 실행합니다. privileged container의 process는 본질적으로 **호스트의 root와 동일**합니다. 기본값은 false입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount는 container에 사용할 **proc mount 유형**을 나타냅니다. 기본값은 readonly paths와 masked paths에 대해 container runtime 기본값을 사용하는 DefaultProcMount입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | 이 **container가 읽기 전용 root filesystem**을 가지는지 여부입니다. 기본값은 false입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **GID**입니다. 설정되지 않으면 runtime 기본값을 사용합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container가 **non-root 사용자로 실행되어야 함**을 나타냅니다. true이면 Kubelet은 runtime에서 image를 검증하여 UID 0(root)으로 실행되지 않는지 확인하고, 그렇다면 container 시작을 실패시킵니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **UID**입니다. 지정하지 않으면 image metadata에 명시된 사용자로 기본 설정됩니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | container에 적용될 **SELinux context**입니다. 지정하지 않으면 container runtime이 각 container마다 무작위 SELinux context를 할당합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container가 **non-root user로 실행**되어야 함을 나타냅니다. true이면 Kubelet은 runtime에서 image를 검증하여 UID 0(root)으로 실행되지 않도록 확인하고, 그렇다면 container 시작을 실패시킵니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process의 entrypoint를 실행할 **UID**입니다. 지정하지 않으면 image 메타데이터에 지정된 user가 기본값이 됩니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | container에 적용될 **SELinux context**입니다. 지정하지 않으면 container runtime이 각 container에 대해 무작위 SELinux context를 할당합니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | 이 container에서 사용할 **seccomp options**입니다. |
|
||||
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | 모든 containers에 적용되는 **Windows 전용 설정**입니다. |
|
||||
|
||||
## Practical workload review checklist
|
||||
|
||||
Pod 또는 workload template를 검토할 때는 `spec.securityContext`와 `containers`, `initContainers`, `ephemeralContainers` 아래의 모든 container-level `securityContext`를 확인하십시오. container-level 필드는 Pod-level 기본값을 덮어쓸 수 있으므로, 안전해 보이는 Pod default가 모든 container의 안전을 보장하지는 않습니다.
|
||||
Pod 또는 workload template를 검토할 때는 `spec.securityContext`와 `containers`, `initContainers`, `ephemeralContainers` 아래의 모든 container-level `securityContext`를 확인하십시오. container-level 필드는 pod-level 기본값을 덮어쓸 수 있으므로, 안전해 보이는 pod 기본값이 모든 container의 안전을 보장하지는 않습니다.
|
||||
|
||||
우선적으로 점검할 고위험 조합:
|
||||
|
||||
- `privileged: true`, 특히 `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports, 또는 runtime socket mounts와 함께 사용된 경우
|
||||
- `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH`, `DAC_OVERRIDE` 같은 capabilities 추가
|
||||
- 공격자가 제어하는 code를 실행할 수 있는 containers에서 `allowPrivilegeEscalation: true` 또는 미설정
|
||||
- `seccompProfile: Unconfined`, `procMount: Unmasked`, 또는 민감한 workload에서 runtime profiles 누락
|
||||
- 신뢰할 수 없는 input을 처리하는 workload에서 writable root filesystem 또는 광범위한 writable volume mounts
|
||||
- multi-tenant namespaces에서 CPU, memory, 또는 ephemeral-storage requests와 limits 누락
|
||||
- `privileged: true`, 특히 `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports, 또는 runtime socket mounts와 함께 사용되는 경우.
|
||||
- `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH`, `DAC_OVERRIDE` 같은 capabilities 추가.
|
||||
- 공격자가 제어하는 code를 실행할 수 있는 container에서 `allowPrivilegeEscalation: true`이거나 설정되지 않은 경우.
|
||||
- `seccompProfile: Unconfined`, `procMount: Unmasked`, 또는 민감한 workload에서 runtime profiles가 없는 경우.
|
||||
- 신뢰할 수 없는 input을 처리하는 workload에서 writable root filesystem 또는 광범위한 writable volume mount.
|
||||
- 멀티테넌트 namespace에서 CPU, memory, ephemeral-storage requests와 limits가 없는 경우.
|
||||
- 비현실적인 pod-level `spec.resources` 예산이 없거나, Pod `resize` subresource에 대해 `patch` 또는 `update` 권한을 가진 주체가 있는 경우. 지원되는 cluster에서는 Pod를 다시 만들지 않고도 실행 중인 CPU와 memory desired state를 변경할 수 있기 때문입니다.
|
||||
|
||||
대부분의 application workloads에는 non-root UID로 실행하고, `runAsNonRoot: true`를 설정하며, `allowPrivilegeEscalation: false`를 설정하고, 모든 capabilities를 drop한 뒤 필요한 최소한만 다시 추가하고, `seccompProfile: RuntimeDefault`를 사용하며, read-only root filesystem을 선호하고, host namespaces, hostPath mounts, privileged mode는 피하는 것이 좋은 baseline입니다.
|
||||
Resource controls는 `securityContext`의 일부는 아니지만, 가용성 경계를 정의하므로 같은 workload 점검 과정에서 함께 검토해야 합니다. 최신 Kubernetes는 container-level `resources` 외에도 `spec.resources` 아래 pod-level에서 CPU, memory, hugepage 예산을 정의할 수 있습니다. sidecar가 있는 Pod는 한 container에 개별 limits가 없어도 전체 Pod envelope로 제한될 수 있지만, local ephemeral storage는 별도의 `ephemeral-storage` limits, `emptyDir.sizeLimit`, LimitRanges, 그리고 ResourceQuotas가 여전히 필요합니다. 또한 in-place resize 요청 후에는 Pod spec의 desired resources와 `status.containerStatuses[].resources`를 비교하십시오. resize가 실패했거나 대기 중이면 `spec`에는 요청한 값이 남아 있지만, kubelet은 이전 runtime allocation을 유지하고 `PodResizePending` condition을 보고할 수 있습니다.
|
||||
|
||||
cluster 수준에서는 가능하다면 [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) namespace labels를 사용해 Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)를 강제하십시오. 지원 가능한 namespaces에는 `restricted`를 사용하고, 일반 application namespaces에는 최소한 `baseline`을 사용하며, privileged 예외는 좁게 유지하고, 문서화하며, 신뢰할 수 있는 platform namespaces 또는 node pools로 격리하십시오.
|
||||
대부분의 application workload에는 non-root UID로 실행하고, `runAsNonRoot: true`를 설정하며, `allowPrivilegeEscalation: false`를 설정하고, 모든 capabilities를 제거한 뒤 필요한 최소한만 다시 추가하고, `seccompProfile: RuntimeDefault`를 사용하며, 읽기 전용 root filesystem을 선호하고, host namespaces, hostPath mounts, privileged mode는 피하는 것이 좋은 기준입니다.
|
||||
|
||||
cluster 수준에서는 가능한 경우 [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) namespace labels를 사용해 Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/)를 강제하십시오. 지원되는 namespace에는 `restricted`를 사용하고, 일반 application namespace에는 최소한 `baseline`을 사용하며, privileged 예외는 좁고 문서화되어 있어야 하고 신뢰할 수 있는 platform namespace 또는 node pool로 격리해야 합니다.
|
||||
|
||||
## References
|
||||
|
||||
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
|
||||
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
- [https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/)
|
||||
- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/)
|
||||
- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
|
||||
- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pod-level-resources/)
|
||||
- [https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/](https://kubernetes.io/docs/tasks/configure-pod-container/resize-container-resources/)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Reference in New Issue
Block a user