Ingress Controller 를 사용하여 같은 도메인에서 subpath 로 웹서비스를 분리하는 방법은 각 서비스마다 Ingress 를 만들고, '/' path 는 무조건 포함시키는 방법입니다. 한가지 단점은 root path '/' 는 처음 만든 Ingress 가 먼저 선점하게 됩니다.

 

물론 이 방법은 '/' 가 경로가 반드시 필요한 서비스가 2개 이상이면 적용할 수 없지만 그런 경우는 없다고 가정합니다.

 

예를 들어 Jupyterlab 은 '/' 경로를 반드시 필요로 합니다. '/jupyter' 를 호출할 때 jupyterlab 이 호출되게 Ingress 의 subpath 를 지정하려면 다음과 같이 작성하면 됩니다.

 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
  name: jupyterlab
  namespace: jupyterlab
spec:
  rules:
  - host: jupyterlab.myserver
    http:
      paths:
      - backend:
          serviceName: jupyterlab
          servicePort: 80
        path: /jupyter
  - host: jupyterlab.myserver
    http:
      paths:
      - backend:
          serviceName: jupyterlab
          servicePort: 80
        path: /

이렇게 하면 'http://jupyterlab.myserver/jupyter' 가 호출되거나 'http://jupyterlab.myserver/' 가 호출되어도 jupyterlab 이 잘 연결됩니다.

 

여기에 '/echoserver' 를 subpath 로 연결되게 추가하고 싶으면 새로운 Ingress 를 만들면 됩니다.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
  name: echoserver
  namespace: jupyterlab
spec:
  rules:
  - host: jupyterlab.myserver
    http:
      paths:
      - backend:
          serviceName: clusterip
          servicePort: 80
        path: /echoserver
  - host: jupyterlab.myserver
    http:
      paths:
      - backend:
          serviceName: clusterip
          servicePort: 80
        path: /

여기서 두번째에 들어가 '/' 는 소용이 없습니다. Nginx 에서는 처음 입력된 순서에 의해서 location 이 결정되기 때문에 'http://jupyterlab.myserver/' 를 호출하면 첫번째 생성한 jupyterlab ingress 가 적용되기 때문입니다. 

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

웹서비스를 인터넷에 노출시키기 위해서는 Cloud Provider 가 제공하는 Load Balancer 나 On-Prem 에서 Load Balancer 나 Ingress Controller 를 사용해야 합니다. Ingress Controller 를 사용할 때 원래의 Client IP 를 확인하는 방법은 다음과 같습니다.

 

여기서 사용하는 Ingress Controller 와 Pod 의 Web Server 는 Nginx 를 사용했습니다.

1. [ 인터넷 ] ---> [ Ingress Controller ] ---> [ Pod (Web Server) ]

가장 기본적인 방법으로 추가 세팅없이도 바로 original client ip 를 알 수 있습니다.

 

Ingress Controller 를 설치하기 위해 node label 을 세팅합니다.

$ kubectl label --overwrite node k1-node01 node-role.kubernetes.io/ingress=true

그리고 아래의 Ingress Controller yaml 로 설치합니다.

$ vi nginx-controller.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-configuration
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  enable-underscores-in-headers: "true"

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
kind: ConfigMap
apiVersion: v1
metadata:
  name: udp-services
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nginx-ingress-serviceaccount
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  name: nginx-ingress-clusterrole
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - endpoints
      - nodes
      - pods
      - secrets
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - services
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - patch
  - apiGroups:
      - "extensions"
    resources:
      - ingresses/status
    verbs:
      - update

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: nginx-ingress-role
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
rules:
  - apiGroups:
      - ""
    resources:
      - configmaps
      - pods
      - secrets
      - namespaces
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - configmaps
    resourceNames:
      # Defaults to "<election-id>-<ingress-class>"
      # Here: "<ingress-controller-leader>-<nginx>"
      # This has to be adapted if you change either parameter
      # when launching the nginx-ingress-controller.
      - "ingress-controller-leader-nginx"
    verbs:
      - get
      - update
  - apiGroups:
      - ""
    resources:
      - configmaps
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - endpoints
    verbs:
      - get

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: nginx-ingress-role-nisa-binding
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: nginx-ingress-role
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: nginx-ingress-clusterrole-nisa-binding
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: nginx-ingress-clusterrole
subjects:
  - kind: ServiceAccount
    name: nginx-ingress-serviceaccount
    namespace: ingress-nginx

---

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      serviceAccountName: nginx-ingress-serviceaccount
      hostNetwork: true
      nodeSelector:
        node-role.kubernetes.io/ingress: "true"
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.0
          args:
            - /nginx-ingress-controller
            - --configmap=$(POD_NAMESPACE)/nginx-configuration
            - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
            - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
            - --publish-service=$(POD_NAMESPACE)/ingress-nginx
            - --annotations-prefix=nginx.ingress.kubernetes.io
          securityContext:
            allowPrivilegeEscalation: true
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE
            # www-data -> 33
            runAsUser: 33
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          ports:
            - name: http
              containerPort: 80
            - name: https
              containerPort: 443
          livenessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10
          readinessProbe:
            failureThreshold: 3
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 10

Ingress Controller 가 설치 되었으면 echoserver 로 Pod 에서 어떻게 Client IP 를 받는지 확인할 수 있습니다.

echoserver 소스 :  https://kubernetes.io/docs/tutorials/services/source-ip/

 

Using Source IP

 

kubernetes.io

$ kubectl create ns echoserver

$ vi echoserver.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: source-ip-app
  namespace: echoserver
  labels:
    run: source-ip-app
spec:
  replicas: 1
  selector:
    matchLabels:
      run: source-ip-app
  template:
    metadata:
      labels:
        run: source-ip-app
    spec:
      containers:
      - image: k8s.gcr.io/echoserver:1.4
        name: source-ip-app
$ vi echoserver-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: clusterip
  namespace: echoserver
  labels:
    run: source-ip-app
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    run: source-ip-app
  type: ClusterIP

echoserver 는 nginx 서버이며 head 의 값을 출력하는 로직을 가지고 있습니다.

busybox 로 echoserver 출력 내용을 확인해 보겠습니다. 그러기 위해서 먼저, echoserver 의 service ip 를 확인한 후 curl 로 http request 를 호출해 봅니다.

$ kubectl get svc -n echoserver 
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
clusterip   ClusterIP   10.233.35.118   <none>        80/TCP    66s
# kubectl run busybox -it --image=busybox --restart=Never --rm -n echoserver

If you don't see a command prompt, try pressing enter.
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop qlen 1
    link/ipip 0.0.0.0 brd 0.0.0.0
3: gre0@NONE: <NOARP> mtu 1476 qdisc noop qlen 1
    link/gre 0.0.0.0 brd 0.0.0.0
4: gretap0@NONE: <BROADCAST,MULTICAST> mtu 1462 qdisc noop qlen 1000
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
6: eth0@if404: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 5e:8e:b0:19:be:56 brd ff:ff:ff:ff:ff:ff
    inet 10.233.125.19/32 scope global eth0
       valid_lft forever preferred_lft forever

/ # wget -qO - 10.233.35.118
CLIENT VALUES:
client_address=10.233.125.19
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://10.233.35.118:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
connection=close
host=10.233.35.118
user-agent=Wget
BODY:
-no body in request-

pod 에서 service 를 통해 web server 를 호출하면 client_address 에 client ip 가 제대로 출력됩니다. 그러나, Ingress Controller 호출하는 경우에는 다음과 같습니다.

 

Ingress Controller 는 k1-node01 (192.168.30.12) 에 떠있고, k1-node05 (192.168.30.20) 에서 echoserver 를 호출해 보겠습니다.

echoserver 를 위한 Ingress 를 생성합니다.

$ vi echoserver-ingress.yaml 

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: echoserver
  namespace: echoserver
spec:
  rules:
  - host: echoserver.ip
    http:
      paths:
      - backend:
          serviceName: clusterip
          servicePort: 80
        path: /

k1-node05 서버에서 echoserver.ip 도메인을 hosts 파일에 등록하고, echoserver 를 호출합니다.

$ cat /etc/hosts
192.168.30.12    k1-node01    echoserver.ip
192.168.30.20    k1-node05



$ curl -X GET echoserver.ip -H 'Host: echoserver.ip'
CLIENT VALUES:
client_address=192.168.30.12
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://echoserver.ip:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=*/*
host=echoserver.ip
user-agent=curl/7.47.0
x-forwarded-for=192.168.30.20
x-forwarded-host=echoserver.ip
x-forwarded-port=80
x-forwarded-proto=http
x-original-uri=/
x-real-ip=192.168.30.20
x-request-id=15b32d8bb2a8945f0dfebf3fae29c736
x-scheme=http
BODY:
-no body in request-

client_address 에는 Ingress Controller 가 떠있는 서버의 ip 가 들어오고, header 의 x-forwared-for 값에 original client ip 가 출력되는 것을 알 수 있습니다.

 

실제 Ingress Controller 의 echoserver 에 대한 config 값은 다음과 같습니다.

proxy_set_header X-Request-ID           $req_id;
proxy_set_header X-Real-IP              $the_real_ip;
             
proxy_set_header X-Forwarded-For        $the_real_ip;
             
proxy_set_header X-Forwarded-Host       $best_http_host;
proxy_set_header X-Forwarded-Port       $pass_port;
proxy_set_header X-Forwarded-Proto      $pass_access_scheme;
             
proxy_set_header X-Original-URI         $request_uri;
             
proxy_set_header X-Scheme               $pass_access_scheme;
             
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;

Pod 의 nginx 에서 client ip 에 original client ip 를 출력하고 싶을 때는 pod nginx 에 다음과 같은 설정이 필요합니다. (추가 확인 필요)

set_real_ip_from  192.168.30.0/24;
real_ip_header    X-Forwarded-For;

set_real_ip_from 은 ingress controller 가 실행될 수 있는 서버의 cidr 입니다.

 

 

2. [ 인터넷 ] ---> [ Google or Azure LB ] ---> [ Pod (Web Server) ]

Cloud Provider (Google or Azure) 의 LB 를 이용하고 Service 의  LoadBalancer type 으로 웹서비스를 한다면 아래와 같이 Service 의  externalTrafficPolicy 값을 local 로 지정하면 됩니다. local 로 지정하면 LB 에서 바로 Web Server Pod 가 떠 있는 서버로만 접근되기 때문에 다른 서버를 통해서 연결될 때 client ip 가 해당 서버의 ip 로 들어가는 것을 방지해 줍니다.

---
kind: Service
apiVersion: v1
metadata:
  name: example-service
spec:
  ports:
  - port: 8765
    targetPort: 9376
  selector:
    app: example
  type: LoadBalancer
  externalTrafficPolicy: Local

Azure 부분은 한국 MS 의 박인혜 차장께서 알려주셨습니다.

 

3. [ 인터넷 ] ---> [ AWS ELB (classic lb) ] ---> [ Pod (Web Server) ]

Classic LB 에 proxy protocol 을 enable 하고, Service 의 annotations 에 다음과 같이 설정합니다.

# Enable PROXY protocol
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: '*'
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: 'https'
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-west-myarn-long-entry-obfuscated-here

 

4. [ 인터넷 ] ---> [ AWS NLB ] ---> [ Ingress Controller ] ---> [ Pod (Web Server) ]

Ingress Controller 의 config 에 다음과 같이 설정합니다.

use-proxy-protocol: "true"
real-ip-header: "proxy_protocol"

 

AWS NLB 의 각 타겟 그룹에 Proxy Protocol V2 를 설정한 후,  Ingress Controller 의 Service annotations 에 다음과 같이 설정합니다.

# by default the type is elb (classic load balancer).
service.beta.kubernetes.io/aws-load-balancer-type: nlb
# Enable PROXY protocol
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: 'tcp'

 

※ AWS 와 Google 의 경우에는 테스트 해보지 못했습니다. 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

Ingress Controller 를 활용한 웹서비스에 TLS 를 적용하는 방법 중 가장 쉬운 방법은 Ingress Controller 에 TLS 를 적용하는 방법입니다. 이 방법은 client 와 Ingress Controller 까지 https 로 통신하고 Ingress Controller 와 web server 와는 http 로 통신하게 됩니다.

아래의 방법은 Ingress Controller 는 미리 설치되어 있다고 가정합니다.

 

먼저, letsencrypt 로 접속하여 3개월간 무료로 인증서를 받는 방법을 알아봅니다.

 

1. 필요 패키지 설치 (Ubuntu 16.04 기준)

# apt-get update
# apt-get install software-properties-common
# add-apt-repository universe
# sudo add-apt-repository ppa:certbot/certbot
# sudo apt-get update
# sudo apt-get install certbot python-certbot-nginx

 

2. 인증서 다운로드

중요한 것은 인터넷에서 해당 도메인으로 로컬 서버에 접속이 되어야 하며 (Inbound 가능) standalone 을 사용할 때 로컬에 80 포트는 unbind 되어 있어야 합니다. 아래와 같은 경우는 외부에서 cloudnativeday.kr, www.cloudnativeday.kr, test.cloudnativeday.kr 도메인이 갖는 ip address 가 내 로컬 서버여야 한다는 의미입니다. 정확히는 해당 ip address 로 외부에서 내 서버로 연결이 가능해야 합니다.

# certbot certonly --standalone --cert-name cloudnativeday.kr -d cloudnativeday.kr,www.cloudnativeday.kr,test.cloudnativeday.kr

 

인증서 발급이 완료되면 다음과 같은 디렉토리에 인증서가 생성되어 보입니다. archive 디렉토리와 심볼릭 링크가 있는 live 디렉토리가 있는데 live 디렉토리를 활용합니다. 그리고, crt 는 fullchain.pem 을, key 는 private.pem 을 사용합니다.

 

# ls -al /etc/letsencrypt/archive/cloudnativeday.kr/
total 24
drwxr-xr-x 2 root root 4096 Apr  7 21:31 .
drwx------ 3 root root 4096 Apr  7 21:31 ..
-rw-r--r-- 1 root root 1931 Apr  7 21:31 cert1.pem
-rw-r--r-- 1 root root 1647 Apr  7 21:31 chain1.pem
-rw-r--r-- 1 root root 3578 Apr  7 21:31 fullchain1.pem
-rw------- 1 root root 1704 Apr  7 21:31 privkey1.pem


# ls -al /etc/letsencrypt/live/cloudnativeday.kr/
total 12
drwxr-xr-x 2 root root 4096 Apr  7 21:31 .
drwx------ 3 root root 4096 Apr  7 21:31 ..
lrwxrwxrwx 1 root root   41 Apr  7 21:31 cert.pem -> ../../archive/cloudnativeday.kr/cert1.pem
lrwxrwxrwx 1 root root   42 Apr  7 21:31 chain.pem -> ../../archive/cloudnativeday.kr/chain1.pem
lrwxrwxrwx 1 root root   46 Apr  7 21:31 fullchain.pem -> ../../archive/cloudnativeday.kr/fullchain1.pem
lrwxrwxrwx 1 root root   44 Apr  7 21:31 privkey.pem -> ../../archive/cloudnativeday.kr/privkey1.pem
-rw-r--r-- 1 root root  692 Apr  7 21:31 README

 

 

인증서를 성공적으로 생성하고 나면, Ingress Controller 에서 사용하기위해서 인증서를 secret tls 타입으로 생성합니다.

 

3. secret tls 생성

# kubectl create secret tls cloudnativeday-certs --key /etc/letsencrypt/live/cloudnativeday.kr/privkey.pem --cert /etc/letsencrypt/live/cloudnativeday.kr/fullchain.pem --namespace cloudnative

타입은 secret tls 로 하고, key 는 private.pem 을, cert 는  fullchain.pem 을 사용합니다.

 

 

4. tls ingress 생성

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  name: cloudnative-kr
  namespace: cloudnative
spec:
  tls:
  - secretName: cloudnativeday-certs
    hosts:
    - cloudnativeday.kr
    - www.cloudnativeday.kr
  rules:
  - host: cloudnativeday.kr
    http:
      paths:
      - backend:
          serviceName: nginx-cloudnative
          servicePort: 80
        path: /
  - host: www.cloudnativeday.kr
    http:
      paths:
      - backend:
          serviceName: nginx-cloudnative
          servicePort: 80
        path: /

http 로 들어오면 자동으로 https 로 redirect 됩니다. 왜냐하면 기본 값이 nginx.ingress.kubernetes.io/ssl-redirect: "true" 이기 때문입니다. 일반 http 와 다른 부분은 tls 부분입니다. secret 과 인증서가 적용될 도메인명을 적으면 됩니다.

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

Kubernetes 는 RBAC 이 디폴트 접근 제어 권한으로 User account 와 RBAC 을 적절히 사용하면 효과적인 접근 제어를 할 수 있습니다.

예를 들어, Kubernetes Cluster 에 접근할 수 있는 사용자 seungkyua 를 새로 만들고 해당 사용자는 seungkyua 네임스페이스에만 접근 가능하게 설정하고 싶은 경우가 있을 수 있습니다.

또한 seungkyua 네임스페이스 접근 안에서도 pods, replicasets, deployments, services 만 생성, 조회, 수정, 삭제권한만 주고 싶을 때도 있습니다.

 

이러한 세팅은 아래와 같은 절차를 거쳐야 합니다. 물론 Kubernetes 는 RBAC 사용으로 세팅되어 있다고 가정합니다.

  1. 신규 namespace 생성
  2. User account 생성 (client key 와 client crt 생성)
  3. 새로운 namespace 에 제한적으로 접근할 수 있는 권한 생성 (role 생성)
  4. 3번의 새로운 User account 와 3 번의 role 을 연결 (rolebinding 생성)
  5. kubectl 이 사용할 새로운 config context 를 만들고 연결

 

1. 신규 naemspace 생성

# kubectl create namespace seungkyua

 

2. 새로운 User account 생성

  • client private key 생성 
# openssl genrsa -out seungkyua.key 2048

 

  • crt 생성을 위한 csr 생성
# openssl req -new -key seungkyua.key -subj "/CN=seungkyua/O=Kubernetes Korea Group" -out seungkyua.csr

 

  • client cert 파일 생성
# openssl x509 -req -in seungkyua.csr -CA /etc/kubernetes/ssl/ca.crt -CAkey /etc/kubernetes/ssl/ca.key -CAcreateserial -out seungkyua.crt -days 10000

 

3. 새로운 namespace 로 접근 role 설정

# vi role.yaml

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
  name: seungkyua-manager
  namespace: seungkyua
rules:
  - apiGroups:
      - ""            # core api
      - "extensions"
      - "apps"
    resources:
      - "deployments"
      - "replicasets"
      - "pods"
      - "services"
    verbs:
      - "get"
      - "list"
      - "watch"
      - "create"
      - "update"
      - "patch"
      - "delete"


# kubectl create -f role.yaml

 

4. User 와 Role 을 연결 (rolebinding 생성)

# vi rolebinding.yaml

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: seungkyua-manager-rolebinding
  namespace: seungkyua
subjects:
  - kind: User         # User or ServiceAccount
    name: seungkyua
roleRef:
  kind: Role
  name: seungkyua-manager
  apiGroup: rbac.authorization.k8s.io
  

# kubectl create -f rolebinding.yaml

 

5. Kubectl config context 생성

  • 인증을 위한 사용자 정보 등록 (key, crt 로 접속)
# kubectl config set-credentials seungkyua --client-certificate=/root/ahnsk/private-certs/seungkyua.crt --client-key=/root/ahnsk/private-certs/seungkyua.key --embed-certs=true

 

  • context 생성
# kubectl config get-clusters NAME cluster.local # kubectl config set-context seungkyua@k1 --cluster=cluster.local --user=seungkyua --namespace=seungkyua

 

  • kubernetes 접속
# kubectl config get-contexts
CURRENT   NAME                             CLUSTER         AUTHINFO           NAMESPACE
*         kubernetes-admin@cluster.local   cluster.local   kubernetes-admin   
          seungkyua@k1                     cluster.local   seungkyua 


# kubectl config use-context seungkyua@k1


# kubectl config get-contexts
CURRENT   NAME                             CLUSTER         AUTHINFO           NAMESPACE
          kubernetes-admin@cluster.local   cluster.local   kubernetes-admin   
*         seungkyua@k1                     cluster.local   seungkyua          seungkyua

 

Kubernetes 에 접속하여 해당 계정이 해당 네임스페이스에만 접속 권한이 있는지 확인

# kubectl get pods

No resources found.



# kubectl get pods -n defaults

Error from server (Forbidden): pods is forbidden: User "seungkyua" cannot list resource "pods" in API group "" in the namespace "defaults"

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com