6W - PKI 구조, CSR 리소스를 통한 api 서버 조회
개요
이 문서에서는 보안에 가장 기본이 되는 x509 형식의 파일과, 그 기반이 되는 PKI 시스템에 대해서 알아본다.
추가적으로 쿠버네티스의 api 서버에 통신할 때 x509 인증서를 통해 인증하는 방법도 다룬다.
이번 문서는 보안에 관한 이론을 먼저 다룰 것이기에 지식 부분이 상당한 분량을 차지한다.
또한 api 서버의 인증에 대해서는 x509 인증서 말고 다양한 방식이 존재하며 이는 다음 글에서 다룬다.
사전 지식
암호화 알고리즘의 종류
본격적으로 들어가기에 앞서, 어떤 암호화 알고리즘이 있고 어떻게 분류되는지 간략하게 다룬다.
관련 알고리즘의 실습은 이 사이트를 많이 활용하게 될 것이다.
다양한 암호화 알고리즘에 대해 조금 더 깊게 들어간 내용은 암호 알고리즘 총괄 참고.
간단한 결론은 다음과 같다.
대칭키
대칭키 알고리즘은 암호화를 하는데 쓰이는 키가 복호화를 하는데 쓰이는 키와 같은 알고리즘들을 말한다.
대칭키를 이용한 암호화는 함수 연산이 적어서 암호화, 복호화간 속도가 빠르다는 장점이 있다.
그래서 서버와 클라 간에 이 대칭키가 안전하게 서로 공유만 될 수 있다면, 대칭키를 이용하는 것이 가장 좋다.
비대칭키
비대칭키 알고리즘은 암호화를 하는 키와 복호화를 하는 키가 다른 암호 알고리즘을 말한다. 이 둘은 개인키, 공개키라고도 부르는데, 이는 용도에 따라 부르는 명칭일 뿐, 둘 간의 다른 특징이 있는 것은 아니다. 키가 2개 필요하고, 이 두 키는 같지 않기 때문에 비대칭키라고 부른다.
키의 특성을 기준으로 부를 때 비대칭키라고 하지만, 용도 관점에서는 공개키 알고리즘이라고 부른다.
공개키 알고리즘이란 표현이 훨씬 많이 쓰이고, 이 문서의 내용인 Public Key Infrastructure도 공개키를 명칭으로 삼는다.
그래서 이 단락에서는 비대칭키라고 하나, 앞으로는 공개키라고 부르는 경우가 훨씬 많을 것이다.
비대칭키는 연산 과정이 조금 더 복잡하기에 대칭키에 비해 연산이 조금 더 오래 걸린다.
그래서 비대칭키는 서버와 클라 간에 사용할 대칭키를 안전하게 교환하는 방법으로서 주로 활용된다.
비대칭키 알고리즘의 특징은 말 그대로 공개키를 가진 사람은 개인키로 암호화된 텍스트를 읽을 수 있다는 것이다.
반대로, 공개키로 암호화한 텍스트는 개인키를 가진 자만이 읽을 수 있다.
- 클라는 서버의 공개키로 복호화가 가능한 암호문만이 서버의 암호문이라고 검증할 수 있다.
- 어떤 텍스트가 누구에 의해 쓰여졌는지 확인할 수 있게 되기에, 일종의 사인(서명) 효과를 가질 수 있다.
- 그래서 이를 활용하는 것을 디지털 서명(Digital Signature)라고 부른다.
- 또한 클라가 공개키를 이용해 암호화한 내용은 서버만이 읽을 수 있다.
- 클라의 텍스트가 악의적인 사용자가 가져가는 것을 방지할 수 있다.
해시
해시 함수는 위의 다른 암호화 방식과 다르게, 암호화 이후에 복호화가 불가능한 함수이다. 기본적으로 복호화가 불가능한 이유는 암호화 과정에서 기존 텍스트의 정보를 많이 버리면서, 일대일 대응 함수가 아니기 때문이다. 가령 x의 제곱이 4라고 한다면, 여기에서 x는 -2일 수도 있기에 2라고 단정지을 수가 없다. 결국 암호화된 출력값(digest라고도 함)을 아무리 뜯어봐도, 원래 텍스트가 무엇이었는지는 알 수 없게 된다. 그래서 이 놈은 좀 암호화라고 표현하기 보다는, 그냥 해싱했다, 해시 연산을 거쳤다고 말하는 게 조금 더 어감이 와닿는다.해시 알고리즘은 다음의 중요한 특징을 가지며, 이 특징을 가져야만 의미가 있다.
- 어떤 텍스트가 들어가도 나오는 출력값은 저마다 고유해야 한다.
- 그래서 입력값이 뭐였는지는 몰라도, 두 출력값을 보고 두 입력값이 같은지 다른지 알 수 있다.
- 텍스트 간 단 한 글자만 달라도 출력값은 완전히 다른 모양을 가지고 있다.
- 이로부터 패턴을 찾아내는 것이 불가능하며, 출력값으로부터 입력값을 알 수 없다.
- 들어간 텍스트의 길이에 상관없이 무조건 일정한 길이로 출력된다.
- 나머지 연산 같은 압축되는 과정이 들어가기 때문
이 특징들로 인해 해시 알고리즘은 매우 중요한 의미를 가지게 되며, 암호화폐에서도 활용된다.
주로 활용되는 방식은 데이터 무결성 검증이다.
서버는 클라이언트에게 자신의 평문과 다이제스트를 같이 보낸다.
그러면 클라는 평문을 같은 해시 함수로 돌려서 다이제스트가 같은지 비교하여 데이터가 변조되지 않았는지 검증할 수 있다.
참고로, 출력값의 길이가 정해졌다는 뜻은 비둘기 집의 원리(n개의 집에 무작위로 n+1마리의 비둘기가 들어가면 최소한 한 집에는 두 마리의 비둘기가 들어가있다)가 적용된다는 뜻이기도 하다.
그래서 해시 충돌(다른 입력값, 같은 결과)이 일어나기도 하는데, 이를 해소하기 위해 해시 체이닝 등의 기법이 존재한다.
레인보우 테이블이라 하여, 나올 수 있는 모든 해시값을 테이블로 정리해두는 공격 방법이 존재한다.
해시 함수는 기본적으로는 키라는 개념이 없다.
그래서 어떤 해시 함수에 대해 가능한 모든 입력값을 넣어보고 테이블화시켜두는 것이다.
그러면 한 입력값은 한 출력값만 가지기에, 한 출력값을 보고 입력값을 유추해낼 수 있게 된다.
PKI 사전 지식
PKI는 웹 환경에서 공개키가 공캐키를 인증해주는 방식을 확장하여 구성된 생태계이자 시스템이다.
데이터 전송 간 암호화(Encryption in transit), 그리고 통신 주체가 신뢰 있는 통신을 지원하기 위해 나왔다.
자세한 내용은 PKI를 참고하고, 여기에서는 설명을 간략화한다.
PKI가 성립하게 된 배경에는 다음의 여러 요구사항이 있었다.
- 전송 간 암호화
- 통신 간에 누군가 내용을 뜯어볼 수 없어야 함
- 대화를 하고 있다는 사실을 숨길 수 없다면, 최소한 내용을 해석할 수 없어야 함
- 무결성
- 데이터가 위변조될 수 없어야 함
- 위의 사항이 충족되더라도 위변조는 발생할(아래에서 자세히 다루겠다) 수 있으므로, 이것도 확실하게 보장돼야 한다.
- 신원 검증
- 내가 통신하려는 상대가 내가 의도한 대상이 맞는지 확인할 수 있어야 한다.
- 또한, 그 상대가 신뢰할 수 있는 대상인지 역시 확인할 수 있어야 한다.
이중 PKI가 성립함으로서 가장 핵심적으로 해결된 것은 신원 검증인데, 이 신원 검증의 원리를 보기 위해서 각 다른 요구사항들에 대한 방법론도 간단하게는 살펴볼 필요가 있다.
전송 간 암호화
전송 간 암호화는 어떻게 보장될 수 있는가?
기본 아이디어로는 다음의 방법을 떠올릴 수 있다.
- 비대칭키를 잘 이용해 첫번째 통신 간 암호화를 달성한다.
- 실제 통신은 대칭키를 이용하며, 이 대칭키가 서로 공유되는 과정에는 반드시 비대칭키 암호화를 활용한다.
비대칭키를 통해 대칭키를 안전하게 공유한 뒤에, 실제 통신은 대칭키를 활용하여 빠르게 통신을 가능하게 한다.
이 방법 밖에도 몇가지 방법과 기법이 있는데, 핵심은 어떻게 서버와 클라만이 알 수 있는 대칭키를 공유하는가에 대한 것이다.
지금부터는 대칭키를 어떻게 안전하게 공유하는지를 먼저 보겠다.
가장 간단한 방법 - 기본 RSA
통신 흐름 상에서 블록 속 내용물은 실제로 보내지는 데이터를 말한다.
이때 데이터가 암호화된 경우, 블록에 색깔을 칠하고 그 위에 어떤 것으로 암호화됐는지 나타냈다.
Diffie Hellman
Diffie Hellman(지옥 남자..) Key Exchange는 비대칭키를 이용하지 않고도 서버와 클라 간의 대칭키를 만들 수 있는 방법이다.[1]
이건 지극히 수학적인 방법만 이용해서 단 두번의 트래픽 흐름으로 서로만 알 수 있는 대칭키를 만드는데 모듈러 연산을 활용한다.
나중에 잠시 보겠지만, 이 방법을 각종 통신에 활용하기도 하는데, 대신 이로 인해 추가적인 트래픽이 발생하기도 한다.
RSA 추가 - Nonce
중간자 공격을 막는 방법은 임의의 난수(Nonce)를 만드는 것이다. 일단 서로 공개키를 알고 있다고 가정한다. 어차피 공개키는 막 뿌릴 수 있는 거라 어떻게든 서로의 것만 알면 된다. (참고로 서로 간 검증이 필요한 경우에 이렇게 하는 것이고, 그냥 서버만 공개키가 있어도 다를 건 없다.) 이제 이 공개키는 상대만 읽을 수 있으므로, 난수를 공개키로 암호화해서 보내는 것이다. 그리고 서로가 그렇게 난수를 주고 받으며 난수가 제대로 돌아왔는지 체크가 완료되면 대칭키를 만들어 보내는 방식. 공개키로 암호화된 난수는 중간에 해커가 있더라도 뜯어볼 수 없기 때문에 위변조가 불가능하다. 즉, 공개키를 이용해 상대가 내가 통신하고자 하는 상대가 맞다는 것을 검증할 수 있는 것이다!이 방식은 충분히 효과적이기에 이를 더 심화시키는 여러 바리에이션이 있다.
그러나 당장은 몇 가지 아쉬운 지점이 있다.
- 여러 서버와 여러 클라가 통신하는 상황에서, 각 주체는 통신하는 대상과 전부 알아서 대칭키를 만든다.
- 대칭키를 지나치게 많이 만드는 것도 궁극적으로는 보안 위협을 높일 수 있고, 비효율적이다.
- 대칭키의 만료 시간도 정할 수 없다.
- 아래에서 볼 무결성을 보장하기 힘들다.
- 전송 간 데이터 손실, 에러 가능성을 보장해줄 수 없다.
- 추가적으로, 공개키를 가지는 것만으로는 상대의 신원을 검증할 수 없다.
- 막말로 서버라 생각한 공개키가 해커의 것이라면 어떡할 것인가?
여기에서 굳이 다른 단점까지 거들먹거리는 이유는, 결국 이 방식이 오늘날 많이 사용되고 있기 때문이다.
아래에서 볼 실제 프로토콜들에서도 궁극적으로는 RSA를 심화시킨 방식을 많이 사용한다.
무결성
두번째 조건이었던 데이터 위변조 방지에 대한 방법들을 알아보자.
전송 간 암호화를 달성한다고 한다고 해서 데이터가 위조되지 않았다고 보장할 수는 없다.
서버와 클라 간에 통신이 여자저차 암호화됐어도, 데이터가 오고 가는 과정에서 데이터가 변질되지 않게, 서로가 명확하게 의도한 대로 전달됐음을 보장하기 위한 수단이 추가적으로 필요하다.
이를 위해 요구되는 속성이 바로 무결성으로, 무결성이란 말 그대로 데이터가 일관되고 신뢰성이 있어야 한다는 것이다.
해시
위에서 살펴본 해시는 데이터의 위변조를 방지할 수 있는 확실한 특징을 가지고 있다.
가령 서버에서 a라는 데이터를 보낼 때, 이 데이터를 해싱을 한번 한 후에 그 다이제스트를 같이 보낸다고 쳐보자.
그렇다면 클라는 a를 받은 이후에 서버가 사용한 해시 함수를 그대로 적용하여 같은 값이 나오는지 보고, 데이터가 변조되지 않았다고 확인할 수 있다.
하지만 당연히 이 방식은 신원 검증이 불가능하다.
게다가 이건 받은 데이터의 무결성만을 체크할 뿐이다.
MAC
Message Authentication Code는 대칭키를 이용해 위변조를 막는 방법이다.[2]
해시에서 다이제스트를 붙여서 데이터를 보내듯이, 대칭키를 이용해 메시지 인증 코드(MAC)를 만든 뒤 그걸 데이터에 붙여 보낸다.
서버가 a라는 데이터를 대칭키로 암호화한 값과 평문을 같이 보낸다면 같은 대칭키를 가지고 있는 클라는 암호문을 복호화 하여 데이터가 변조됐는지 체크할 수 있다.
MAC은 다양한 다른 암호화 방식과 결합되어 분화된다.
이 그림은 엄밀하게 원래 정의된 HMAC 알고리즘과 다르다.
원래 HMAC은 대칭키로부터 두 개의 키를 생성하고, 이 두 키를 활용해 두 번의 해싱을 진행한다.
둘을 같이 활용한다는 것을 핵심 삼아 단순화시켰다.
MAC 방식은 신뢰되는 대칭키를 가진 상대를 신뢰할 수 있다는 장점이 있다는 점에서, 일반 해시보다 훨씬 안전한 알고리즘이다.
그러나 해시와 마찬가지로 일단 기본 평문을 보내도록 설계돼있기에, 이 방식 자체로는 평문에 대한 아쉬움이 있다.
그래서 [[#전송 간 암호화]]에서 다룬 알고리즘과 혼합하여, 평문 자체는 암호화를 시키고 이를 복호화한 후 무결성을 검증하는 식으로 많이 활용된다.
무결성의 한계
PKI의 요구사항 중 마지막, 신원 검증이 왜 필요한지를 알아보기 위해 잠시 여기에서 무결성만 추구할 때 발생하는 문제를 짚어본다.
언뜻 보면 MAC 방식은 서버와 클라만이 가진 대칭키를 이용한다는 점에서, 대칭키로 암호화됐다는 것만으로 상대의 신원이 어느 정도 보장되는 것이 아닌가 하는 생각이 들 수 있다.
그러나 여기에는 부인 봉쇄(non-repudiation)를 하지 못한다는 치명적인 문제가 발생한다.
부인 봉쇄란 통신 간 주체가 상대의 메시지를 부인하는 상황을 막는 것을 이야기한다.
가령 서버가 b라고 데이터를 보냈다고 해보자.
이때 클라는 b를 받고, 이를 대칭키로 무결성까지 검증했다.
그러나 이걸 받은 클라는 a를 받았다고 스스로 위변조를 한 다음에 대칭키로 MAC을 만들어 a에 대한 무결성도 마쳤다고 서버한테 큰소리를 칠 수 있다..
클라 역시 대칭키를 가지고 있으니, MAC을 만드는 방법을 알고 있기에 가능한 상황인 것이다.
그럼 반대로 서버는 어떨까?
반대로 서버도 클라가 이런 식으로 자신 마음대로 데이터를 위변조할 수 있다는 상황 때문에 클라가 보내오는 데이터를 믿지 못한답시고 부인할 가능성이 있다.
즉 통신 주체 간 믿을 수 없는 상황이 만들어질 여지를 막아야 하기 때문에 바로 부인 봉쇄가 필요한 것이다.
부인 봉쇄가 이뤄지지 않으면, 서로 속고 속이는 관계 속에서 데이터의 신뢰성을 확보할 수 없어 무결성을 확보했다고 할 수 없다.
그래서 엄밀한 차원에서, 무결성은 서로가 믿을 수 있는 상대라는, 신원 검증이라는 하나의 큰 속성을 추가적으로 만족해야만 하는 것이다.
무결성을 어떻게 정의하냐에 따라 다르겠지만, 나는 무결성이 신뢰성을 포함하는 개념이라고 생각한다.
그러면에서는 부인을 할 수 있는 가능성 역시 신뢰성을 떨어뜨리는 요건이라고 생각한다.
다만 전문적인 자료에서는 부인 방지 역시 큰 틀에서 무결성과 따로 보안의 한 요소로서 보는 것 같다.[3]
신원 검증
무결성의 하위 탭으로 들어갈 수도 있다고 생각하지만, 이를 위한 방법론들을 조금 더 크게 다루기 위해 신원 검증은 별도로 큰 단락에서 다룬다.
RSA 디지털 서명
디지털 서명은 윗단락에서 다룬 무결성을 충족하는 방법 중 하나이다.
(참고로 디지털 서명에는 ElGamal, DSA 등의 다른 방법들도 있다.)
- MAC 기반이니 무결성도 검증된다.
- 서버의 공개키로 복호화하니 서버의 개인키로 암호화했음이 확실시된다.
- 서버 신원이 검증된다.
- 클라는 서버의 개인키를 모르니 멋대로 MAC을 만들어서 땡깡 부리는 게 불가능하다!
RSA 디지털 서명은 여태 소개한 방식들 중에서는 무결성을 검증하는 가장 좋은 방법이라고 할 수 있다.
개인키로만 서명이 가능하기 때문에, 클라 측에서 마음대로 조작을 할 수 없으니 부인 봉쇄까지 완료된다.
이를 통해 명확하게 상대를 신뢰할 수 있는 발판이 생기는 것이다!
중간 정리
지금까지 전송 간 암호화, 무결성을 달성할 수 있는 각종 방법들을 알아봤다.
이들을 조합하면 일차적으로 서버와 클라가 안전하게 통신할 수 있는 토대가 마련된다.
그러나 아직도 해결해야 할 문제가 하나 남았는데, 그것은 서버의 공개키를 믿는 과정이다.
RSA 디지털 서명으로 신원 검증이 달성된다고 이야기했지만, 사실 디지털 서명은 각 주체만이 서명을 할 수 있다는 점에서 서명자가 특정되니 검증된다고 하는 것이다.
그런데 만약에 클라가 접촉하려는 서버가 알고보니 악의적인 무언가였다면?
지금까지 이야기 나온 것들은 그저 서버가 공개키를 클라에게 주었을 때 이를 기반으로 서로가 안전하게 통신을 하는 방법에 대한 이야기이다.
하지만 공개키야 당장 나도 만들어서 뿌릴 수 있고 너도 뿌리고 피아노 위에서 탭댄스를 추는 원숭이도 뿌릴 수 있는 것이다.
즉, 정말로 상대에게서 공개키를 받았을 때 이 공개키가, 이 공개키를 가진 상대가 신뢰할 수 있는 대상인가를 믿을 만한 추가적인 지지 기반이 필요하다.
공개키 신뢰 방법 - CA와 X509
그래서 Certifate Authority(CA)가 탄생했다.
KDC 만큼 막강한 능력들을 가진 것은 아니지만, 최소한 인터넷 환경에서 신뢰할 수 있는 공개키를 가진 인증 기관이다.
즉 CA의 공개키는 무조건 믿을 수 있다고 전세계적으로 합의가 되어 있고, 실제로 모든 기기에 기본적인 CA의 공개키가 저장돼있다.
(엄밀하게는 공개키를 포함하고 있는 인증서인데, 아래에서 보겠다.)
전세계에서 인정된 특정 기관들이 CA로서 지정되어 모든 통신에서 신뢰의 기반을 형성할 수 있도록 해준다.
이를 통해 인터넷 환경에서는 신뢰 관계를 넓힐 토대가 마련되는데, 바로 인증서(certificate)를 이용하는 것이다.
위의 RSA 디지털 서명은 통신에 있어서 무결성을 검증하기 위해 활용되기도 하지만, 무결성과 상대 신원을 검증할 수 있다는 특성 상 다른 용도로도 활용될 수 있다.
아주 간단한 발상이다.
- CA는 신뢰할 수 있다.
- 그렇다면 CA가 신뢰해주는 서버가 있다면?
- 해당 서버도 신뢰할 수 있다!
클라가 서버를 신뢰할 수 있게 되는 흐름을 조금 더 구체화시키면 이렇게 된다.
- CA가 어떤 서버의 공개키에 대해 CA의 개인키로 암호화해준다.
- CA가 암호화해줬다, 즉 디지털 서명을 해주었다 하여 인증서라고 부른다.
- 클라는 CA의 공개키를 가지고 있으니 해당 암호문을 복호화할 수 있다.
- CA에게 서명을 받은 서버의 공개키이니, 이 공개키는 신뢰할 수 있다!
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:00:00:00:00:01:44:4e:f0:42:47
# 서명에 활용된 알고리즘
Signature Algorithm: sha256WithRSAEncryption
# 서명 발행자
Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA
# 유효기간
Validity
Not Before: Feb 20 10:00:00 2014 GMT
Not After : Feb 20 10:00:00 2024 GMT
# 인증된 주체 = 서명 대상
Subject: C=BE, O=GlobalSign nv-sa, CN=GlobalSign Organization Validation CA - SHA256 - G2
# 주체의 공개키 정보
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c7:0e:6c:3f:23:93:7f:cc:70:a5:9d:20:c3:0e:
...
Exponent: 65537 (0x10001)
X509v3 extensions:
# 이 인증서의 용도 지정
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
# 서버 공개키의 식별자
X509v3 Subject Key Identifier:
96:DE:61:F1:BD:1C:16:29:53:1C:C0:CC:7D:3B:83:00:40:E6:1A:7C
X509v3 Certificate Policies:
Policy: X509v3 Any Policy
CPS: https://www.globalsign.com/repository/
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.globalsign.net/root.crl
Authority Information Access:
OCSP - URI:http://ocsp.globalsign.com/rootr1
# 인증한 기관 공개키 식별자
X509v3 Authority Key Identifier:
keyid:60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B
# 디지털 서명 내용
Signature Algorithm: sha256WithRSAEncryption
46:2a:ee:5e:bd:ae:01:60:37:31:11:86:71:74:b6:46:49:c8:
이것이 X509 인증서의 예시다.
대충 중요한 부분들만 보자면..
- Data - 인증서의 핵심 내용이 담긴다.
- Issuer - 발행자, 즉 인증 기관을 말한다.
- Validity - 이 인증서의 유효기간을 말한다.
- Subject - 서명된 대상, 여태까지의 설명으로라면 서버라고 보면 된다.
- Subject Public Key Info - 서버의 공개키!
- X509 extensions - 추가적인 정보들..
- Signature - 인증 기관의 디지털 서명 값이 담긴다.
공개키와, 공개키의 소유 주체가 일단 담겨져 있다.
그리고 이 공개키를 인증하기 위한 발행자(인증 기관)가 누군지, 이 발행자가 서명한 내용도 담겨있다.
이 인증서를 받은 클라는 일단 내용을 확인해, 발행자의 정보를 읽고 발행자의 공개키를 통해 디지털 서명 부분을 복호화하여 이 인증서가 정말 유효한지 검증한다.
검증이 되면, 이제 이 공개키를 누가 가지고 있는지, 누가 서명해줬는지가 확실하게 판명난다.
인증서의 형식을 보면 알겠지만, 인증서에는 단순하게 공개키 뿐만 아니라 공개키의 주체의 정보도 담긴다.
CA 역시 자신의 공개키가 자신 것이라는 것을 명확히 하고자 인증서 형태로 공개키를 모든 기기에 저장한다.
CA는 self-signed, 즉 자체 서명된 인증서를 발급한다.
자신의 공개키에 대해 자신이 개인키로 인증서를 발급하는 형태를 말한다.
이 인증서에 CA의 공개키가 담겨있으므로 CA로부터 서명된 다른 인증서의 위변조를 확인할 수 있다.
/etc/ssl/certs
에 관련한 정보들이 담겨 있는 것을 확인할 수 있다.
X.509 인증서는 대체로 pem, crt, pub 등의 확장자를 가지고 있다.
대체로 pem을 쓰는 추세이긴 하나, 어떤 확장자를 쓰는지는 저마다 다양한 것 같다.
모든 인증서를 한 파일로 보고 싶다면 해당 디렉토리의 ca-certificates.crt
파일을 열어보면 된다.
실제 통신이 일어날 때 인증서를 검증할 때는 이렇게 클라에 내장된 신뢰되는 공개키를 이용해 디지털 서명의 유효성을 밝힐 수 있다.
pem 파일을 열어보면 이런 식으로 작성돼있는데, 이 값은 기본적으로 base64로 인코딩돼있다.
그러나 이걸 디코딩한다고 바로 열어볼 수는 없는 게, 정확하게는 DER이라는 형식으로 인코딩된 것이 다시 base64로 인코딩돼있다..
그리고 DER 형식을 열어보려면 별도의 툴이 필요하다.
openssl x509 -noout -text -in chain.pem
간단하게는 openssl 쓰는 게 최고다.
Public Key Infrastructure
X509 인증서는 다른 공개키를 인증하기 위해 마련된 인증서이다.
그리고 그 인증서가 유효한지는 신뢰되는 공개키를 이용해 검증할 수 있다.
결과적으로 신뢰된 공개키를 이용해 다른 공개키를 검증하는 신뢰의 체인 구조가 성립한다는 것을 알 수 있다.
공개키가 공캐키를 인증해주는 방식을 확장하여 구성된 생태계이자 시스템이 바로 PKI, 공개키 인프라다.
왜 이렇게까지 거창하게 또 개념화시키느냐, 이 세상에 CA가 많지 않기 때문이다.
그래서 CA로부터 인증을 받은 인증 기관들이 또다시 CA의 역할을 하고, 이로부터 다른 인증 기관을 인증하고..
하는 꼬리에 꼬리에 무는 신뢰 관계를 형성하여 인터넷 환경에서 활용하게 되는데, 이러한 총체적인 인프라 구조를 PKI라고 칭하는 것이다.
각 인증기관들은 전부 인증서를 가지고 있고, 이로부터 다른 서버의 공개키를 인증해주는 인증서의 체인을 통해 신뢰할 대상을 넓혀나간다.
브런치 도메인에 인증서를 보면, 인증서 계층이 3단계로 이뤄진 것을 볼 수 있다.
탑 레벨에 위치한 인증서를 루트 인증서라 부른다.
현재 이 인증서는 인증하는 대상 키를 4E ~~
로 명시하고 있는 것이 보인다.
중간 체인 역할이 되는 인증서를 보면 인증 기관 키 ID가 위와 일치하는 것을 확인할 수 있다.
이 중간 인증서를 인증한 공개키는 루트 인증서를 통해 인증됐음을 알 수 있는 부분이다.
한편 중간 인증서에도 마찬가지로 인증서 대상 키 ID가 있다.
이 인증서를 통해 인증된 공개키 ID는 위와 같은 과정으로 최하위 인증서에서 확인할 수 있다.
최하위 인증서를 인증한 공개키 ID는 중간 인증서를 통해 인증된 공개키 ID와 일치한다.
인증이 되는 구조는 알았으니, 이제 마지막으로 두 가지를 볼 것이다.
인증서가 발행되는 과정, 클라가 인증서와 공개키를 받는 과정이다.
인증서 발행 과정 - ACME
그러면 CA로부터 어떻게 인증서를 받아낼 수 있는가?
단순하게만 말하자면, CA의 개인키를 이용해 서버의 공개키를 암호화한 값을 디지털 서명 부분에 달아주기만 하면 된다.
하지만 위에서 본 X.509 형식에 맞춰서 인증서 발행에 몇 가지의 정형화된 순서가 생겼다.
- 서버에서 Certificate Signing Requests 파일을 생성하여 CA에 전달한다.
- 줄여서 CSR이라 하는 이 파일에는 요청 서버의 정보와 서버의 공개키가 담긴다.
- CA는 이 CSR을 토대로 디지털 서명을 넣어 인증서를 발급한다.
로컬 환경에서는 openssl을 이용해 직접 만든 CA로부터 발급받는 과정을 실습해볼 수 있다.
그러나 인터넷 환경에서는 정말로 모두에게 신뢰되는 기관으로부터 인증서 발행을 받아야 하는데, 최근 조금 정형화돼어 쓰이는 방법 중 하나는 ACME 프로토콜이다.
Automatic Certificate Management Environment는 웹 환경에서 도메인을 가진 서버에서 쓰일 인증서를 발급하는 프로토콜이다.[4]
이 프로토콜은 정해진 규격에만 따르면 서버 신원 검증, 인증서 발급 및 갱신까지도 자동화한다.
해당 RFC8555에 따르면, 보통의 인증서 발행 흐름은 다음과 같았다.
- 서버에서 자신의 도메인을 담은 CSR 생성
- CA 웹 페이지에 복붙
- CA는 도메인 소유권을 검증하기 위해 몇 가지 방법 제공
- CA에서 제시한 웹 사이트 챌린지 성공(그냥 html 태그를 헤더에 넣으라 이런 거)
- CA에서 제시한 도메인 챌린지 성공(TXT 레코드에 어떤 값 넣기)
- CA에서 제시한 이메일 챌린지 성공(도메인 이메일로 전달된 내용을 CA에게 재전달)
- 검증 완료 후 CA에서 발행한 인증서를 다운로드
이 과정이 수동으로 이뤄지기에, 인증서 발급 과정은 매우 귀찮은 일이고 추가적으로 갱신 시에도 비슷한 짓을 반복해야 한다.
그래서 나온 프로토콜이 ACME이다.
ACME에서는 일단 서버는 CA에 계정을 등록해야 한다.
(더 엄밀하게는 CA로부터 인증서를 받아주고 서버의 신원을 먼저 검증하는 앞단인 Registration Authority가 있을 수 있다.)
다른 트래픽 그림들과 다르게, 이 프로토콜은 완벽하게 HTTP, 즉 7계층에서 수행되는 프로토콜이다.
그래서 요청과 응답을 조금 명확하게 하고자 화살표는 요청을 보내는 쪽을 나타내도록 표현했다.
응답의 내용은 화살표 아래 배치했다.
다만 마지막 부분 쯤에 반대로 화살표는 예외로, 시간이 조금 걸릴 수 있기 때문에 그 간극을 표현하고자 한 것이니 주의.
긴단하게 말하자면 다음의 순서를 따른다고 보면 된다.
- 서버가 인증서 주문
- 이 주문 때 CSR에서 채워야 하는 다양한 내용들을 바디로 전달한다.
- CA에서 챌린지 제시
- CA마다 다양한 챌린지를 커스텀할 수 있는데, ACME를 만든 ISRG에서는 다음의 기본 챌린지를 제시한다.
- http-01
- 받은 토큰 값으로
{도메인}/.well-known/acme-challenge/{토큰}
URL 200 반환하게 만들기 - 인증서 받기 전이니 무조건 80 포트로 http 통신
- 받은 토큰 값으로
- dns-01
- 받은 토큰 값을 반환하는
_acme-challenge.{도메인}
TXT 도메인 레코드 등록
- 받은 토큰 값을 반환하는
- 서버는 챌린지 설정 완료 후 CA에게 검사해달라 찡찡
- CA는 이 검사를 여러 번 수행할 수도 있다.
- 주문이 준비됐다고 뜰 때까지, 주기적으로 서버는 폴링을 통해 주문 상태를 확인해야 한다.
- 주문이 준비됐다면 정식으로 CSR을 건네서 인증서를 달라 찡찡댄다.
- CA는 초기 인증서 주문 당시 값과 CSR 값을 또 비교한다.
- 인증서 발행에 조금 시간이 걸릴 수 있어서 화살표를 반대로도 표시했다.
- 인증서 url을 받으면 그 경로로 인증서를 받으면 된다!
이 프로토콜에서 CA는 3개의 오브젝트와 그에 대한 상태값을 가진다.
프로토콜 흐름 상으로 각 오브젝트를 정리하면 이렇게 된다.
- Order - 주문
- 서버 요청에 해당하는 오브젝트로 pending 상태로 생성된다.
- 이게 ready 상태가 되면 비로소 서버는 인증서를 내놔라 요구할 수 있다.
- Authorization - 권한
- 도메인에 대한 권한을 체크하는 오브젝트로 pending 상태로 생성된다.
- 한 Order에 대해 여러 개의 권한을 체크할 수 있다.
- 모든 권한이 체크돼야만 Order가 ready 상태가 된다.
- Challenge - 챌린지
- 각 Authoritization 오브젝트마다 제시하는 챌린지 오브젝트로 pending 상태로 생성된다.
- 한 Authoritization에 대해 여러 개의 챌린지를 제시할 수 있다.
- 한 챌린지만 성공하더라도 권한은 체크된다.
- 이래서 Authrization과 Challenge가 별도의 오브젝트로 분리돼있는 것이다.
아마 이 프로토콜을 직접적으로 사용할 일은 없을 것이다.
이 프로토콜은 Let's Encrypt를 관리하는 ISRG에서 만들었는데, let's encrypt는 이걸 활용해 인증서 자동 발급과 갱신을 할 수 있는 여러 에이전트를 만들고 있기 때문이다.
도메인에 대한 완전한 소유권이 있다면 DNS 챌린지를 하는 게 상대적으로 쉬울 수 있다.
HTTP 챌린지의 경우 무조건 80 포트를 사용하도록 제한되고 있기 때문에, 조금 더 제한적인 상황에 부닥칠 수 있다.
서버 인증서 확인 과정 - TLS
마지막으로, 서버의 신뢰된 인증서를 어떻게 클라가 받아들이는지 보자.
이번에도 웹 프로토콜을 기준으로 설명하고자 한다.[5]
어차피 PKI를 기반으로 하는 다른 프로토콜들도 결국 방식은 거의 다 비슷할 것이다.
Transport Layer Security 프로토콜은 PKI 시스템을 활용하는 가장 많이 알려진 보안 프로토콜 중 하나이다.
실질적으로 이 문서에서 PKI를 설명하기 위해 활용한 전반적인 구조도 최종적으로는 TLS를 설명할 목적으로 작성됐다..
엄밀하게 TLS(1.2)는 Record Protocol, Handshaking Protocol 두 가지 계층으로 나뉘어져 있다.
Record Protocol은 하위 계층에 속하는 프로토콜로, 상위 계층(핸드쉐이킹)에서 설정된 방식에 의거해 데이터 암호화, 단편화, 압축 등의 작업을 수행하는 레코드 층에 대한 프로토콜이다.
이 문서에서는 간단하게만 넘기는데, 이 프로토콜이 성립하기 위해서는 마스터 시크릿이라는 값이 생겨야 한다는 것만 짚어둔다.
(자세한 내용은 PKI#Record Protocol 참고)
Handshaking Protocol
핸드쉐이킹 프로토콜은 위 레코드 프로토콜을 세팅하고 검증하기 위한 절차를 담은 프로토콜이다.
핸드쉐이킹 과정은 대충 4번 오고 간다. 여기에 에러가 발생하거나, 중간에 암호 방식을 교체한다던가 하는 각종 추가적인 과정이 있을 수 있긴 한데, 이것들은 생략했다. 그런 트래픽은 항상 발생하는 것은 아니기도 하고, 핵심 플로우에 해당하진 않는다. 빨간색 블록은 클라이언트의 신원까지 검증하는 mutual TLS로 핸드쉐이킹이 이뤄질 때만 발생하는 추가적인 트래픽이다.- 클라이언트 헬로
- 클라이언트에서 사용 가능한 각종 버전과 알고리즘 리스트를 전달한다.
- 이때 클라 난수를 같이 전달한다.
- 서버 헬로
- 클라에게 받은 버전이나 알고리즘 등에서 서버 측도 사용 가능한 것을 선별하여 보낸다.
- 여기에는 최대한 최신 버전을 쓴다, 뭐 이런 몇 가지 규칙이 있다.
- 서명 받은 서버의 인증서를 전달한다.
- 이때 서명한 기관이 상위 기관을 두는 식으로 꼬리를 문다면 체인 인증서를 한꺼번에 전부 전달한다.
- 이때 서버 난수를 같이 전달한다.
- 대칭키 교환 방법 중, 디피 헬만 알고리즘이 선택된 경우에는 대칭키 교환을 위한 추가 메시지를 보낸다.
- 클라에게 받은 버전이나 알고리즘 등에서 서버 측도 사용 가능한 것을 선별하여 보낸다.
- 클라 피니쉬
- 클라이언트는 인증서 검증을 시작한다.
- 최상단에 서버 인증서가 있고, 여기에서 발행자(Issuer) 값을 꺼낸다.
- 체인 인증서가 이 다음에 있으면 발행자 값을 토대로 서버를 인증하는 인증 기관이 적힌 인증서를 찾는다.
- 그 인증서에는 인증 기관의 공개키가 적혀있을 테니, 그것으로 서버 인증서를 검증한다.
- 꼬꼬무한다..
- 마지막 남은 인증서의 발행자 값은 로컬 환경에 저장된 루트 CA의 인증서로 검증한다.
- 검증을 마치고 Pre Master Secret 값을 만들어 서버의 공개키로 암호화하여 보낸다.
- 디피 헬만 방식이라면 암호화를 거치지 않는다고 한다.
- 클라이언트는 인증서 검증을 시작한다.
- 서버 피니쉬
- 문제 없으면 그냥 끝 날린다!
레코드 프로토콜에서 필요한 값 중 하나는 마스터 시크릿이란 값인데, 이 값은 클라 난수 + 서버 난수 + Pre Master Secret을 합쳐 만들어진다.
각 난수는 암호화되지 않았지만, Pre Master Secret는 클라가 서버의 공개키로 암호화했기에 서버만이 복호화할 수 있다.
이를 바탕으로 Master Secret을 만들면 둘만의 대칭키를 만드는데 활용할 수 있다!
- clusters
- 통신을 하고자 하는 대상 리스트
- 서버의 주소와 해당 서버를 인증하는데 사용될 정보가 들어간다.
- user
- 통신을 하는 주체 리스트
- 주체에게 주소 따위 있을 리 없고 필요도 없으니.. 신원을 검증할 정보를 넣는다.
- contexts
- cluster와 user를 합친 하나의 문맥 리스트
- 당장 통신에 사용되는 것은 current-context라는 필드로 따로 표현된다.
여기에서 헷갈리면 안 되는 것 중 하나가 cluster와 user라는 표현이다.
kubectl에서 먼저 이 형식이 완성됐기에 표현이 이렇게 굳어졌지만, cluster와 user는 그저 통신을 하고 싶은 대상과 주체를 뜻한다.
여러 개의 클러스터와 여러 개의 유저, 여러 개의 컨텍스트를 둘 수 있다.
이를 통해 멀티 클러스터를 운영하거나, 다수의 유저를 이용해 운영할 때 유용하게 사용할 수 있다.
실습 진행
간단 암호화 실습
대칭키 - AES
문자의 길이가 일정 비트를 넘어갈 때마다 암호문의 길이도 커진다.
설정에서 key type을 커스텀하면 내 임의의 대칭키를 넣어보는 것도 가능하다.
utf8에서 숫자와 영어는 1바이트(8비트)이므로, 256비트를 넣기 위해 32 문자를 넣어주고, IV 키는 128 비트여야 해서 16 문자를 넣었다.
비대칭키 - RSA
보통 공개키 알고리즘이라 하면, 이 RSA를 이야기하는 경우가 많다.
TLS 인증에서는 이 방식을 주로 사용하기에 이것과 관련한 요소들을 많이 보게 될 것이고, 이 문서에서도 내용을 진행하며 이 알고리즘에 기반한 내용들을 다룰 것이다.
이 방식은 정수론의 증명된 법칙을 활용한다.
이 개인키와 공개키를 구하는 과정, 이 둘의 암복호화가 서로 동일하다는 것을 증명하는 과정은 매번 보고 매번 이해하고 매번 까먹어서(..) 이제 정리하지 않으려고 한다.
궁금하다면 그냥 꺼무위키[6]를 참고하자.
RSA도 일단 각 키를 만드는 것으로 시작된다.
-----BEGIN PRIVATE KEY-----
MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMXa0RD3mOhvYai8
o0fFPyGSrgjA3+MlAU4d9a5vLSFBkkIQRJ3ctdiFl7kxUZtxFph1+B2xHjiMH8ic
qlXIKfw2//U6JjPNhYxWkWG72v92wDpx894pTuNkp5cs6bVV6oh26598ZTSD6Jwl
eCQC/l9p+9e8rEpTN2GzHIHF6amzAgMBAAECgYEAnds3cpIZLVmwUTAwFdMJy397
2wAHoPKlV+4PVlzdZOssBgl0tX6il13+74Kp2ZsgrANzMj1eHz+tHCHixQ4ub+Ug
4npUPiHiOcoJ4eglmI4UX+e3RVGPlNPgo0d68D9bHZoKpYHL4L2vLDogRZkBm12t
co/AvJPnnKTrU4T7pgECQQDohsjW59AnRTwmD5VhXlSdVbD31nSBjPob27bDXG/t
2BIJOA/JaXLjr91mnR4sUD5lkAWD3CBQE+nXKZF2WZ7lAkEA2dQBU58/qdpXfjKe
/MLaOWRbv5AwRUQSyQEwHjOyKfmRHZou0NKKHhtmLlgMI2ngoQx8YUvfpjZYJnw4
JI+EtwJBAJuph5AetcFkXwTXz9fUD28Ya5UukuYbW2AE8U/NdPzTdheH2UGrfwcf
t2a3bfiaa3sQNDD2zwbsndG1eTSygGUCQQCltjwgIpkrHVjMP7Rls9KSML//lrCy
MRxdYBL8FvXmKt7z9zTAVjsOtmdgwEjTtBtYSYhh+He3Gcar2HpZjfk3AkEAy1VV
/yjT41H0eDaUdLayxLlL9m41FerfXHe9+b2SnqkvYhGy+DU9cZVi9ScAgbyapqHk
3rQBOF6bbTlgR2JHZg==
-----END PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDF2tEQ95job2GovKNHxT8hkq4I
wN/jJQFOHfWuby0hQZJCEESd3LXYhZe5MVGbcRaYdfgdsR44jB/InKpVyCn8Nv/1
OiYzzYWMVpFhu9r/dsA6cfPeKU7jZKeXLOm1VeqIduuffGU0g+icJXgkAv5fafvX
vKxKUzdhsxyBxempswIDAQAB
-----END PUBLIC KEY-----
서명을 하는 방법도 사이트에 나와 있지만, 일단 기본적인 방식만 확인하기 위해 암호화 복호화만 해본다.
8421fbf540c3e4e136ff9982e84df7cca87f9704c27941f936feda79ba2e9c000c562233c2cf048e5c6180543dc086e6144f26fc72f9c8f60a3706415820390e7405f0bb700491a3c2a52ef176040868c23c2c54a842d475d84a37b57f508d114b42c17ad3f2e8688972a6611bc08d42fbc82fcaa9fa445791aab01927346542
이것은 공개키를 이용해 암호화된 내용이다.
이 내용은 개인키를 가지고 있는 서버만이 해독을 할 수 있다.
해시 - MD5
해시 실습은 정말 간단하다.
그냥 일일히 넣어보면서 문자열 크기는 바뀌지 않는데, 값은 어무막지하게 변형되는 것을 확인할 수 있다.
kubeconfig 인증서 분석
본격적으로 쿠버네티스와 통신할 때 사용하는 kubeconfig 파일의 내용을 분석해본다.
간단하게 하기 위해, 로컬 환경에서 Kubernetes v1.32 - Penelope 버전을 띄워 분석을 진행했다.
우리가 흔히 사용하는 kubectl은 .kube/config
파일의 정보를 통해 통신이 이뤄진다.
k config view
간단하게 현재 kubeconfig 파일을 상태를 확인할 수 있는데, 다음의 구조로 된 것을 파악할 수 있다.
cat ~/.kube/config
실제로 해당 파일을 뜯어보면 생략되지 않은 날 것의 데이터를 볼 수 있다.
처음 클러스터를 세팅할 때 나오는 kubeconfig 파일은 유저의 신원을 인증서로 검증한다는 것을 확인할 수 있다.
-data
로 끝나는 필드는 실제 인증서 정보가 base64로 인코딩돼있다.
(이렇게 끝나지 않으면 파일 경로를 명시할 때 쓰이는 필드가 된다.)
클러스터 쪽의 데이터를 디코딩해보면 이렇게 인증서가 들어있는 것이 보인다.
echo "데이터" | base64 -d | openssl x509 -text -noout
간단하게 인증서 내용을 꺼내본다.
공개키 알고리즘으로는 RSA가 사용됐는데, 짧은 비트의 RSA는 취약하다고 알려졌기에 보통 2048비트짜리 키를 만든다.
10년 짜리.. 인증서이고 주체는 kubernetes이다.
또한 발행자 역시 kubernetes로, 이 인증서는 root 인증서임을 알 수 있다.
실제로 이걸 이용해 curl 요청을 날리게 되면 신뢰할 수 없는 루트라는 경고가 출력된다.
확장 정보로, 이 주체 키 식별자가 표시되는데, 이건 바로 아래 두번째 그림과 같이 보자.
같은 방식으로 유저의 인증서도 꺼내본다.
이번에는 kubernetes-admin이란 유저가 cluster-admins란 그룹에 속해있는 상태로, kubernetes에 의해 서명 받은 인증서가 나온다.
이 인증서의 확장 정보에는 이 인증서에 서명한 인증기관 식별자가 담겨 있다.
이 값은 위에서 본 쿠버네티스 루트 인증서의 식별자와 정확히 일치하는 것을 확인할 수 있다.
결과적으로, 최소한 이 config 파일을 가지고 통신할 때 api 서버는 유저의 신원을 이 인증서를 통해 검증한다는 것을 알 수 있다.
다음 주제로 다룰 것이지만, 인증서 방식 말고도 api서버가 들어오는 요청의 신원을 검증하는 방법은 다양한데, 가장 기본적인 방식이 바로 x509인증서이다.
그럼 어떻게 이 인증서가 발급된 걸까?
그 과정은 클러스터의 부트스트랩 과정을 까보면 알 수 있다.
이건 kubeadm의 부트스트랩 과정의 초반 부분이다.
초반에 각종 컴포넌트들이 만들어지기 이전에 인증서들과, config 파일이 만들어지는 것을 확인할 수 있다.
이 과정 상에서 root 인증서가 만들어지고, 이것에 체인이 되는 하위 인증서들이 파생되어 만들어진다.
그 인증서 흔적들은 여기에서 확인할 수 있다.
CSR 리소스 사용하여 특정 신원으로 api 조작하기
이제 직접 인증서를 만들고, 이를 통해 쿠버네티스 api 서버와 통신할 수 있는 kubeconfig 파일을 만들어보자.
x509로 사용자를 쉽게 클러스터에 인증시키는 방법 중 하나는 쿠버네티스에서 제공하는 CSR 리소스를 이용하는 것이다.
방법도 꽤나 간단한데, 자체 키를 만들고 이걸 서명해달라 찡찡대면 된다!
한번 임의의 유저를 가정하고, 그 유저를 관리자 권한을 가지게 해보자.
가장 쉬운 방법은 해당 유저를 system:masters
그룹에 속한다고 표시하는 것이다.
그러나 masters는 rbac관련 제한을 받지 않는, 막강한 권한을 가지게 되는 그룹이라 기본 Admission Control 플러그인으로 제한이 활성화돼있다.
RBAC, 어드미션 컨트롤에 대한 내용은 다음 문서에서 자세히 다루도록 하겠다.
이 실습에서 세팅하는 과정들이 무엇인지 모르겠다면, 미리 쿠버 RBAC, Admission Control 내용을 참고해도 좋다.
클러스터롤바인딩 생성
그러므로 별도의 그룹에 대한 별도의 클러스터롤바인딩을 만들어줄 것이다.
k get clusterrole admin -oyaml
그리고 cluster-admin이라는 롤을 바인딩해줘도 되지만, 이것은 단순히 *을 통해 모든 권한을 가지도록 세팅돼있으므로, 보통의 관리자 권한을 가진 정도의 admin 클러스터롤을 사용해본다.
이 클러스터롤은 aggregationRule을 통해 aggregate-to-admin
이라는 라벨이 붙은 모든 클러스터롤의 값을 획득하도록 돼있다.
반대로 말하자면 관리자에게 어떤 권한을 추가하고 싶다면 해당 라벨을 붙인 클러스터롤을 만들어주기만 하면 이 클러스터롤에 알아서 권한이 추가되므로, 관리를 유연하게 할 수 있다는 장점이 있다.
참고로 이 클러스터롤은 클러스터 범위의 리소스에 대해서는 접근 권한을 세팅하지 않는다.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: test-admin-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:tester
이런 식으로 system:tester
그룹에 속하는 주체는 admin 클러스터롤을 받도록 세팅했다.
키 세팅
RSA 말고 ECC 함수를 사용하는 다른 방법의 비대칭키를 만들어보자.
openssl genpkey -algorithm ed25519 -out private.pem
rsa는 따로 서브 커맨드를 지원하는 방면, ecc를 활용하는 알고리즘에 대해서는 아직 따로 커맨드를 지원하지는 않으므로 그냥 범용적 커맨드를 써야 한다.
ecc를 이용하면, 키 크기가 어무막지하게 작다.
마찬가지로 공개키도 엄청 짧다..!
openssl req -new -key private.pem -subj "/CN=test-user/O=system:tester" -out csr.pem
간단하게 CSR 요청서를 만들었다.
유저 이름은 test-user
, 그룹은 system:tester
가 되도록 CSR를 만든 예시이다.
openssl req -in csr.pem -text -noout
간단하게 내용물을 꺼내보면 이렇게 생겼다.
CSR 양식 파일 작성
cat csr.pem | base64 | tr -d "\n"
다음으로 해줄 작업은 CSR 오브젝트 양식 파일을 작성하는 것이다.
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: test-csr
spec:
signerName: kubernetes.io/kube-apiserver-client
request: 위 출력물
usages:
- digital signature
- key encipherment
- client auth
signerName은 기본적으로 제공되는 것이 한정돼있는데, api 서버에 접근하는 일반 클라이언트는 kubernetes.io/kube-apiserver-client
서명자 이름을 지정하면 된다.
(커스텀 서명자를 지정하는 것도 가능은 하다)
여기에서 바로 subject 이름과 그룹을 명시하는 것도 가능한데, 현재는 이미 csr 파일 자체에 관련 정보가 들어가있으니 세팅하지 않는다.
인증서 받기
현재 CSR 오브젝트가 만들어진 것이 확인된다.
k certificate approve test-csr
어떤 서명자에 대한 요청들은 컨트롤러 매니저에 의해 자동 승인이 되기도 하나, 이 서명자에 대해서는 해당 사항이 없으므로 직접 승인을 해줘야 한다.
참고로 승인을 하기 위해서는 승인과 관련한 적절한 권한을 가지고 있어야 하는데, 처음 클러스터를 만들었을 때 주어지는 주체는 모든 권한이 허용돼있다.
승인이 완료되고, 바로 발행이 완료됐다는 말이 나온다.
그럼 실제로 인증서가 status 필드에 들어가게 된다.
마찬가지로 이값은 base64로 인코딩돼있기에, 뜯어보고 싶다면 먼저 디코딩을 해야 한다.
인증서 내용을 뜯어보면, 세팅한 값 그대로 내용이 들어가 있는 것이 확인된다!
발행자는 kubernetes이고 인증서의 주체는 내가 설정한 유저가 된다.
kubectl get csr test-csr -ojsonpath={.status.certificate} | base64 -d >> cert.pem
이제 테스트 유저를 위한 모든 필요한 값들이 모였다.
k config set-credentials test-admin --client-key private.pem --client-certificate cert.pem
config 파일을 직접 수정하는 것도 가능하지만, kubectl 차원에서 세팅하는 기능도 지원해준다.
파일 경로를 사용하게 되는 경우, 위에서 말했듯이 -data
라는 접미사가 빠진다.
k config set-context test-context --cluster kubernetes --user test-admin
이제 새로운 컨텍스트를 만들고 해당 컨텍스트를 이용하면 된다.
테스트
k auth whoami
SelfSubjectReview를 해보면 이렇게 값이 제대로 들어간 것이 확인된다.
k run test --image nicolaka/netshoot -ti -- zsh
파드를 만드는 등의 행위도 제대로 동작하는 것이 확인된다.
그러나 admin 클러스터롤은 클러스터 범위의 리소스에 대한 접근 권한이 들어가있지 않은 관계로, 관련한 동작은 수행할 수 없다.
그러나 어떤 네임스페이스에 대해 조작할 수 있는지를 지정한 건 아니라 다른 네임스페이스에 대해서도 접근할 수 있긴 하다.
k access-matrix
이건 krew를 통해 설치한 플러그인으로, 어떤 리소스에 어떤 조작을 할 수 있는지 간단하게 표시해주기에 매우 유용하다.
처음 세팅을 진행할 때 사용된 유저는 모든 리소스에 접근이 가능하다.
그러나 방금 세팅된 유저는 꽤나 사용할 수 있는 리소스가 제한적이다.
이 admin은 클러스터를 관리하기 위한 롤이 아니니까 당연하기도 하다.
현재는 클러스터롤바인딩을 만들었지만 보통 롤바인딩으로 특정 네임스페이스의 관리자로서만 권한을 주는 식으로 활용한다.
결론
PKI는 현대 웹 보안 통신의 핵심 기반이 된다.
보안에 대한 개념이 워낙에 많기 때문에 처음 공부할 때는 까다롭지만, 이것을 공부하면 다양한 곳에서 활용할 수 있게 된다.
당장 쿠버네티스도 mTLS 통신을 기본으로 하기 때문에 인증서를 발급받고 통신하기 위해서는 관련한 지식이 필수적으로 요구된다.
이전 글, 다음 글
다른 글 보기
이름 | index | noteType | created |
---|---|---|---|
1W - EKS 설치 및 액세스 엔드포인트 변경 실습 | 1 | published | 2025-02-03 |
2W - 테라폼으로 환경 구성 및 VPC 연결 | 2 | published | 2025-02-11 |
2W - EKS VPC CNI 분석 | 3 | published | 2025-02-11 |
2W - ALB Controller, External DNS | 4 | published | 2025-02-15 |
3W - kubestr과 EBS CSI 드라이버 | 5 | published | 2025-02-21 |
3W - EFS 드라이버, 인스턴스 스토어 활용 | 6 | published | 2025-02-22 |
4W - 번외 AL2023 노드 초기화 커스텀 | 7 | published | 2025-02-25 |
4W - EKS 모니터링과 관측 가능성 | 8 | published | 2025-02-28 |
4W - 프로메테우스 스택을 통한 EKS 모니터링 | 9 | published | 2025-02-28 |
5W - HPA, KEDA를 활용한 파드 오토스케일링 | 10 | published | 2025-03-07 |
5W - Karpenter를 활용한 클러스터 오토스케일링 | 11 | published | 2025-03-07 |
6W - PKI 구조, CSR 리소스를 통한 api 서버 조회 | 12 | published | 2025-03-15 |
6W - api 구조와 보안 1 - 인증 | 13 | published | 2025-03-15 |
6W - api 보안 2 - 인가, 어드미션 제어 | 14 | published | 2025-03-16 |
6W - EKS 파드에서 AWS 리소스 접근 제어 | 15 | published | 2025-03-16 |
6W - EKS api 서버 접근 보안 | 16 | published | 2025-03-16 |
7W - 쿠버네티스의 스케줄링, 커스텀 스케줄러 설정 | 17 | published | 2025-03-22 |
7W - EKS Fargate | 18 | published | 2025-03-22 |
7W - EKS Automode | 19 | published | 2025-03-22 |
8W - 아르고 워크플로우 | 20 | published | 2025-03-30 |
8W - 아르고 롤아웃 | 21 | published | 2025-03-30 |
8W - 아르고 CD | 22 | published | 2025-03-30 |
8W - CICD | 23 | published | 2025-03-30 |
9W - EKS 업그레이드 | 24 | published | 2025-04-02 |
10W - Vault를 활용한 CICD 보안 | 25 | published | 2025-04-16 |
11W - EKS에서 FSx, Inferentia 활용하기 | 26 | published | 2025-04-18 |
11주차 - EKS에서 FSx, Inferentia 활용하기 | 26 | published | 2025-05-11 |
12W - VPC Lattice 기반 gateway api | 27 | published | 2025-04-27 |
관련 문서
이름 | noteType | created |
---|---|---|
TLS downgrade attack | knowledge | 2024-06-20 |
API 접근 제어 우회 | knowledge | 2025-01-13 |
Authentication | knowledge | 2025-01-13 |
openssl | knowledge | 2025-01-18 |
Authorization | knowledge | 2025-01-19 |
cfssl | knowledge | 2025-01-23 |
Prometheus-Adapter | knowledge | 2025-03-04 |
PKI | knowledge | 2025-03-10 |
kube-apiserver | knowledge | 2025-03-12 |
Cert Manager | knowledge | 2025-03-15 |
쿠버네티스 API 구조 | knowledge | 2025-03-19 |
TLS | knowledge | 2025-04-16 |
Istio PeerAuthentication | knowledge | 2025-05-04 |
SPIFFE | knowledge | 2025-05-04 |
E-api 서버 감사 | topic/explain | 2025-01-21 |
E-이스티오 메시 스케일링 | topic/explain | 2025-06-08 |