kuberntes - Mutual TLS

우야·2021년 6월 2일
1
post-custom-banner
  1. 마이크로 서비스간의 통신에 보안 프로토콜이 중요함
    • 왜?
      • 위와 같이 web browser에서 istio ingress gateway까지는 https로 안전하게 데이터가 보호되지만, k8s 내부의 마이크로 서비스간에는 데이터가 변조되거나 손실될 수 있다.
      • 모든 마이크로서비스에서 htts 처리를 위한 로직을 구현하면 문제가 많다.
    • 그럼 어떻게 하지?
      • TLS차원에서 보안이 필요하다.
      • istio를 이용하면 TLS 보안을 해준다.
  2. 그럼 TLS는 뭐지? 다시... 보안 프로토콜 이해
    - TCP/IP는 OSI 7 Layer 를 4개로 단순화 하여 구현
    - TCP/IP는 3,4 계층을 중심으로 한 통신 프로토콜의 계층 집합
  1. 그럼 마이크로 서비스 간에 어떻게 통신을 하는거지?
  1. Istio TLS Option 설정하기

    • Permissive mTLS

      • proxy에 TLS가 설정되어있어도 HTTP통신이 가능하도록 허용
    • Stict mTLS

      • TLS로만 접속을 할수 있음

https://m.blog.naver.com/freepsw/221974847879


그런데... 인증서는 뭐지? 또 어디 사용되는거지?
1. 쿠버네티스는 인증서와 토큰을 이용하여 사용자 인증을 한다고 하는데... 어떻게 처리되고 있는 것일까?
2. 위에서 봤던 TLS인증을 istio가 아닌 kubernetes에서 좀 더 살펴 보려고 한다.

  1. 인증서에 대한 카테고리

    • X.509 Client Certs: X.509 인증서를 이용한 상호 TLS 인증
    • HTTP Authentication: HTTP Authentication을 이용한 사용자 인증
    • OpenID Connect: Google OAuth와 같은 인증 provider를 이용한 인증
    • Webhook 인증: Webhook 인증서버를 통한 사용자 인증
    • Proxy Auth: Proxy 서버를 통한 대리 인증
  2. 쿠버네티스의 인증 및 접근 제어 체계

    Authentication: 접속한 사람의 신분을 시스템이 인증하는 단계입니다. (신분증 확인)
    Authorization: 누가 어떤 권한을 가지고 어떤 행동을 할 수 있는지 확인하는 단계입니다. (view권한, create권한 등)
    Admission Control: 인증과 권한확인 이후에 추가적으로 요청 내용에 대한 검증이나 요청 내용을 강제로 변경할 때 사용합니다.

    • 여기서 말하는 인증은 Authentication이다.
  1. 음...그럼 쿠버네티스 인증처리를 하는 곳은 어디일까?
    • 여러군데가 있겠지만, api-server에서 인증을 하는 상황이 있다.
    • kubeadm으로 kubernetes cluster가 구성되면 PKI 인증서를 생성하는데...
    • kubernetes pod와 같은 resource를 생성하기 위해서 kubelet에서 <--> api-server에 요청시 인증서를 사용하게된다.
  2. 그럼 api-server resource(pod...)는 어떻게 생성 되었지?
    • api-server는 kubeadm으로 kubernetes cluster를 구성하면서 생기는 pod로 static pod중 하나 이다.
    • static pod라는것은 api-server를 통하지 않고 생성되는 pod들이고 /etc/kubernetes/manifest위치에 있다.
    • 이렇게 생성된 api-server는 웹 서버라고 생각하면된다.
    • 웹서버에서 TLS, HTTP auth, OAuth, Webhook, proxy 인증을 한다고 생각하면된다.
  1. 그럼 TLS, SSL인증에 사용되는 X.509 Certificate에 대해서 알아보자.

    • PKI (Public key Infrastructure)

      • PKI는 비대칭 암호화 기술을 이용한 공개키 기반 인증이다.
      • PKI를 이용하면, https하거나 인증(certificate)를 사용할 수 있다.
      • X.509 Certificate는 PKI
    • PKI 기술에 대한 3가지

      • 1. Public Private Key : 각 키마다 고유의 역할을 가짐

        • Public Key: 누구나 가질수 있는 Key
          • 예) Client가 가지고 있음
        • Private Key: Public, Private key pair 소유자만 가지고 있음
          • 예) Server가 가지고 있음
        • Flow
          1. Client에서 Request시 Public Key로 데이터 암호화를 진행
          2. Server에서 Requst를 받으면, Public Key와 pair인 Private Key로만 복호화 진행됨
          3. Server에서 Response로 Private Key로 메시지를 암호화해서 보냄
          4. Client에서 Response로 받은 데이터는 Public Key를 이용하여 pair된 Private key가 맞는지 확인하는 검증을 할 수 있다.
      • 2. Certificate - 인증서

        • Certificate은 Public 키를 포함한 다양한 인증 정보를 담고 있는 문서
          • 인증 체계를 구축하기 위해서는 인증서 발급 기관, 인증서 유효기간, 인증 신원, 서명 알고리즘 등과 같이 다양한 정보들이 필요함
          • Public 키는 단순히 메세지를 암호화하거나 서명된 메세지를 검증하는 키에 불과 하다.
        • 다른 사람이 Private key 없이 Certificate이 담고 있는 내용을 변조하는 것은 불가능
        • Server에서 Certificate 문서 변조를 확인하는 방법은?
          • Certificate 문서안에는 Certificate 문서 전체 내용을 private키를 이용하여 서명한 해쉬값이 포함되어 있다.
          • 그래서 문서 내용 중 한 글자라도 변경이 되면 해쉬값이 달라져서 변조된 문서임을 알아차릴 수 있다.
      • 3. CA (Certificate Authrity) - Certificate 인증해주는 공인 인증 기관

        • 인증서에는 해당 인증서를 발급해준 발급 기관 (Issuer) 정보
        • 공인된 인증 기관에서 발급된 인증서
        • CA도 인증서로 이루어져 있어 Public 키로 인증기관의 유효성을 동일한 메커니즘으로 검사할 수 있습니다.
        • CA도 마찬가지로 CA의 인증서를 발급한 인증 기관(CA의 CA)이 존재하며 이러한 연결고리를 Certificate Chain (인증 체인)이라고 부른다.
        • 인증 체인의 가장 끝에는 Root CA라고 하는 인증기관이 있습니다.
        • Root CA를 이용하여 다른 CA를 검증하고 해당 CA가 최종 Certificate을 인증합니다.
        • 이 Root CA는 따로 인증 기관이 존재하지 않으며 스스로가 스스로를 인증합니다.
        • 그럼 HTTP 통신에서는 어떻게 사용되지?
          • Server에서 공식적으로 발급한 인증키(CA)를 이용하여 데이터를 암호화하여 전달하도록 구성
          • 아하!! 우리가 웹 브러우저를 통해 HTTPS 사이트를 접속할 때 인증기관의 인증서를 따로 전송하지 않아도 정상적으로 연결이 되는 이유는 웹 브러우저 내부적으로 Root CA들을 가지고 있기 때문입니다. (인증 체인을 통해...)
    • Certificate를 이용한 사용자 인증 방법

      1. 인증서 발급

        1. Root CA를 자체 발급 (공인 인증기관 정보)
          • rootCA.pem : root CA인증서
          • rootCA-key.pem : root CA의 키(private key)
        2. Server side PKI key pair (서버 인증서 및 서버 Private key)
          - server.pem : 서버의 인증서
          - server-key.pem : 서버의 키
          2-1. Client side PKI key pair를 생성 (클라이언트 인증서 및 클라이언트 Private key)
          - client.pem : 클라이언트의 인증서
          - client-key.pem : 클라이언트의 키참고, cfssl, easyrsa, openssl등 인증서 생성툴이 있음.
          - csr(certificate Signing Request) : 인증 서명 요청 문서라고 하며, 인증서 생성을 하기 위한 값이 적혀진 json으로 생각하면된다.
          - cert(인증서) : csr과 인증서 생성툴을 사용하여 만들어진 인증서
          - key(private key) : csr과 인증서 생성툴을 사용하여 만들어진 private key
          - pem, crt, key등으로 인증서 및 key 확장자를 사용할 수 있음
      2. TLS가 적용된 HTTPS 웹 서버 구성

        1. Server Certificate 방법

          • 서버 인증을 위한 인증서(Certificate)를 서버에 등록
          • HTTPS 서버 인증에 사용

          HTTP 요청 : 실패
          - curl http://localhost:8443/
          HTTPS 요청 : 성공
          - curl --cacert rootCA.pem https://localhost:8443/

        1. Client Certificate 방법

          HTTS 일반 요청 : 실패
          - curl --cacert rootCA.pem https://localhost:8443/
          HTTPS 클라이언트 인증서 포함 요청 : 성공
          - curl --cacert rootCA.pem --cert client.pem --key client-key.pem https://localhost:8443/

          • 클라이언트 인증은 인증서 + Private Key까지 서버로 전송해야하는데 이유는?
            • 서버인증 : 서버의 주소를 입력하기에 서버가 전달한 서버 인증서의 소유자를 확인할 필요는 없음.
            • 클라이언트인증 : 서버에서는 클라이언트 인증서의 실제 소유자인지 확인해야함, 인증서는 공개되어 있기에 다른 클라이언트 인증서를 가져다 서버로 전송할 수 있음.
    • 그러면... 쿠버네티스에서 제공하는 인증서를 사용해 보자

      • kubeadm을 통해서 생성된 PKI를 이용한 서버 인증을 할수 있다.

      • kubernetes에서의 각 rootCA, 인증서, key의 위치는 어떤것일까?

        rootCA : /etc/kubernetes/pki/ca.crt
        server.pem : /etc/kubernetes/pki/apiserver.crt
        server-key.pem : /etc/kubernetes/pki/apiserver.key
        - 참고로 pem, crt, key는 위에 설명했듯이 확장자만 다른것이다.
        client.pem : /etc/kubernetes/admin.conf안에 client-certificate-data가 있다.
        client-key.pem : /etc/kubernetes/admin.conf안에 client-key-data가 있다.

      • 이 정보들은 nginx를 사용한다면, 아래와 같이 들어갈 수 있다.

        # $HOME/auth/default.conf
        server {
          listen 443 ssl;
          server_name localhost;
          ssl_certificate      /etc/nginx/conf.d/k8s-server.pem;
          ssl_certificate_key  /etc/nginx/conf.d/k8s-server-key.pem;
        
          ssl_verify_client on;
          ssl_client_certificate /etc/nginx/conf.d/k8s-rootCA.pem;
        
          location / {
           root  /usr/share/nginx/html;
           index index.html index.htm;
           }
         }
      • 주의 사항

        • server 인증서가 kubernetes 전용으로 만들어졌기에 localhost로 인증이 안되기 때문에 local server로 테스트시 아래와 같은 설정이 필요하다.

          sudo vi /etc/hosts
          
          127.0.0.1 localhost
          127.0.0.1 kubernetes  # kubernetes --> 127.0.0.1로 매핑
          
          
          curl --cacert k8s-rootCA.pem --cert k8s-client.pem --key k8s-client-key.pem  https://kubernetes:8443/
      • 쿠버네티스에 인증서는 어떻게 더 사용될까?

        • kubelet에서 API 서버 인증서를 인증시 사용하는 클라이언트 인증서
        • API 서버 엔드포인트를 위한 서버 인증서
        • API 서버에 클러스터 관리자 인증을 위한 클라이언트 인증서
        • API 서버에서 kubelet과 통신을 위한 클라이언트 인증서
        • API 서버에서 etcd 간의 통신을 위한 클라이언트 인증서
        • 컨트롤러 매니저와 API 서버 간의 통신을 위한 클라이언트 인증서/kubeconfig
        • 스케줄러와 API 서버간 통신을 위한 클라이언트 인증서/kubeconfig
        • front-proxy를 위한 클라이언트와 서버 인증서
      • 쿠버네티스에 인증서는 어디에 있을까?

        위치 : /etc/kubernets/pki
        
        xxxx@master-node:~$ ls /etc/kubernetes/pki/ -R | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'       
        
        |-----
          apiserver.crt                - apiserver 인증서
          apiserver.key                - apiserver Key
          apiserver-etcd-client.crt    - apiserver에서 etcd사용을위한 client 인증서
          apiserver-etcd-client.key    - apiserver에서 etcd사용을위한 client Key
          
          apiserver-kubelet-client.crt - apiserver에서 kubelet사용을 위한 client 인증서 
          apiserver-kubelet-client.key - apiserver에서 kubelet사용을 위한 client Key
          ca.crt                        - 쿠버네티스 일반 CA
          ca.key                        - 쿠버네티스 일반 CA key
          front-proxy-ca.crt            - kube-proxy에서 apiserver 확장했을때, kube-proxy에서 필요함
          front-proxy-ca.key            
          front-proxy-client.crt        
          front-proxy-client.key
          sa.key                        - 서비스 계정 관리 Private key
          sa.pub                        - 서비스 계정 관리 Public key
          etcd/ : forlder               - etcd 관련 기능에 사용
            ca.crt
            ca.key
            healthcheck-client.crt
            healthcheck-client.key
            peer.crt
            peer.key
            server.crt
            server.key       
      • 그렇다면... 쿠버네티스의 CA를 이용하여 신규 인증서 발급을 할수 있겠네?

        • cfssl 인증서 생성 툴을 이용하여 쿠버네티스에서 제공하는 rootCA의 인증서, key를 이용하여 k8s-new-client라는 PKI를 생성할 수 있다.
        • 이 PKI를 이용하여 새로운 사용자의 kubeconfig를 설정할 수 있음
        cat > k8s-new-client-csr.json <<EOF
        {
          "CN": "k8s-new-client",
          "key": {
            "algo": "rsa",
            "size": 2048
          },
          "names": [
            {
              "O": "system:masters"
            }
           ]
        }
        EOF
        
        # Organazation (O)을 system:masters 라고 지정의미는 쿠버네티스에서는 사용자를 user와 group으로 인식하는데 이때 Organazation (O) 영역을 group으로 인식
        # system:masters 그룹은 쿠버네티스 마스터 그룹을 뜻하는 예약어
        # k8s-new-client라는 유저가 마스터와 동일하게 모든 권한을 소유
        
        # names.O property에 system:masters 설정
        cfssl gencert \
        -ca=k8s-rootCA.pem \              # 쿠버네티스 CA 인증서 사용
        -ca-key=k8s-rootCA-key.pem \      # 쿠버네티스 CA key 사용
        -config=rootCA-config.json \
        -profile=root-ca \
        k8s-new-client-csr.json | cfssljson -bare k8s-new-client
        
        
        ls -l
        
        k8s-new-client-csr.json  # 신규 사용자 인증서 csr json
        k8s-new-client.pem       # 신규 사용자 인증서
        k8s-new-client-key.pem   # 신규 사용자 private key
        
        • 신규 사용자 kubeconfig 설정에 추가
        # 기존 admin 사용자 kubeconfig 파일 복사
        sudo cp /etc/kubernetes/admin.conf $HOME/kubeconfig
        
        sudo chown $(id -u):$(id -g) $HOME/kubeconfig
        
        # kubectl 신규 사용자 설정 - X.509
        
        kubectl config --kubeconfig=$HOME/kubeconfig set-credentials x509 --client-certificate=k8s-new-client.pem --client-key=k8s-new-client-key.pem
        
        kubectl config --kubeconfig=$HOME/kubeconfig set-context kubernetes-admin@kubernetes --user=x509
        
        kubectl config --kubeconfig $HOME/kubeconfig view
        • 신규 사용자로 쿠버네티스 api 서버에 클라이언트 인증
        # api 서버 주소 확인
        kubectl cluster-info
        # Kubernetes master is running at https://XXXX:XXX
        
        # API 서버 주소 및 포트 설정
        API_SERVER_ADDR=XXXX  # 예시) localhost
        API_SERVER_PORT=XXX   # 예시) 6443
        
        # curl - 신규 X.509 사용자 인증
        curl --cacert k8s-rootCA.pem --cert k8s-new-client.pem --key k8s-new-client-key.pem https://$API_SERVER_ADDR:$API_SERVER_PORT/api
        
        # kubectl - 신규 X.509 사용자 인증
        
        kubectl --kubeconfig=$HOME/kubeconfig get pod -n kube-system
        
        # 혹은 직접 파라미터를 이용하여 호출할 수도 있습니다.
        
        kubectl get pod -n kube-system --client-certificate=k8s-new-client.pem --client-key=k8s-new-client-key.pem

https://coffeewhale.com/kubernetes/authentication/x509/2020/05/02/auth01/

profile
Fullstack developer
post-custom-banner

0개의 댓글