PKI
개요
이 문서는 PKI, X.509 형식이 무엇인지 확실하게 정리하기 위해 작성된다.
이를 위해 기본으로 알아야 할 개념이 무척 많기에 이를 따로따로 정리하는 게 가장 좋겠지만, 당장 그러기엔 전문적으로 공부를 해야 할 것 같아 시간이 너무 많이 소요될 것이라고 생각이 들었다.
(전공생들이 정말 부럽다)
그래서 이후에 시간이 나면, 조금 더 지식이 늘면 자연스레 내용을 분화하며 작성할 문서를 분화시키고자 한다.
가시다님의 스터디 AEWS에서 배운 내용을 전적으로 토대로 한다.
PKI의 목적
Public Key Infrastructure와 X.509 인증서 형식 등은 HTTPS 프로토콜을 사용하는 웹 서버를 만들어본 사람이라면 한번이라도 못 들어봤을 수가 없는 용어들이다.
막상 알고리즘을 까보면 굉장히 복잡하게 느껴지고 알아야 할 개념이 많은데, 이 개념이 이뤄져있고, 어떤 식으로 발전해왔는지를 기반으로 정리를 하고자 한다.
목적을 토대로 말하자면 PKI는 데이터 전송 간 암호화(Encryption in transit)를 지원하기 위해 나온 시스템이다.
두 대상(지금부터는 서버와 클라이언트라고 칭한다.)이 대화를 하고자 하는데, 서로만 대화를 하고 싶다.
데이터 전송 간 발생할 수 있는 위험은 위와 같다.
둘이 잘 통신을 하는데, 이 내용을 누군가 뜯어본다던가..
둘이 통신하고 있는 줄 알았는데 알고보니 누군가를 거쳐서 이뤄지고 있었다던가..
인터넷 환경은 내가 누구와 통신하고 있는지도 쉽게 믿을 수가 없다.
그래서 PKI가 성립하게 된 배경에는 다음의 여러 요구사항이 생겼다.
- 전송 간 암호화
- 통신 간에 누군가 내용을 뜯어볼 수 없어야 함
- 대화를 하고 있다는 사실을 숨길 수 없다면, 최소한 내용을 해석할 수 없어야 함
- 무결성
- 데이터가 위변조될 수 없어야 함
- 위의 사항이 충족되더라도 위변조는 발생할(아래에서 자세히 다루겠다) 수 있으므로, 이것도 확실하게 보장돼야 한다.
- 신원 검증
- 내가 통신하려는 상대가 내가 의도한 대상이 맞는지 확인할 수 있어야 한다.
- 또한, 그 상대가 신뢰할 수 있는 대상인지 역시 확인할 수 있어야 한다.
- 다만 여기에서 신원은 서비스를 제공하는 서버 측에 대해서만 엄정하게 요구된다.
- 최소한 클라 입장에서 서버는 정말 통신을 해도 되는지, 신뢰할 만한지 명확하게 보장돼야 한다.
- 클라의 신원을 검증할지는 서버 측에서 결정해야 한다.
참고로 위 두 조건은 정보 보안 3요소 CIA 중 기밀성, 무결성에 해당한다 볼 수 있겠다.
이 조건을 위해서는 데이터를 서로만 볼 수 있는 형태로 암호화하는 과정이 필요하다.
각종 알고리즘의 종류에 대해서는 암호 알고리즘 총괄을 먼저 참고하자.
결론의 특징들만 미리 짚어둔다.
전송 간 암호화
전송 간 암호화는 어떻게 보장될 수 있는가?
암호 알고리즘들을 보면, 사실 아주 직관적으로 떠올릴 수 있는 방식 한 가지, 비대칭키를 활용하는 것이다.
개인키를 통해 암호화를 한 이후, 공개키와 함께 암호문을 뿌리면 모든 대상이 해당 암호문을 복호화할 수 있게 된다.
그러나 그 공개키를 통해 암호화한 암호문은 개인키를 가지고 있는 대상만이 복호화할 수 있다.
그래서 기본 아이디어로는 다음의 방법을 떠올릴 수 있다.
- 비대칭키를 잘 이용해 첫번째 통신 간 암호화를 달성한다.
- 실제 통신은 대칭키를 이용하며, 이 대칭키가 서로 공유되는 과정에는 반드시 비대칭키 암호화를 활용한다.
비대칭키를 통해 대칭키를 안전하게 공유한 뒤에, 실제 통신은 대칭키를 활용하여 빠르게 통신을 가능하게 한다.
이 방법 밖에도 몇가지 방법과 기법이 있는데, 핵심은 어떻게 서버와 클라만이 알 수 있는 대칭키를 공유하는가에 대한 것이다.
지금부터는 대칭키를 어떻게 안전하게 공유하는지를 먼저 보겠다.
가장 간단한 방법 - 기본 RSA
통신 흐름 상에서 블록 속 내용물은 실제로 보내지는 데이터를 말한다.
이때 데이터가 암호화된 경우, 블록에 색깔을 칠하고 그 위에 어떤 것으로 암호화됐는지 나타냈다.
참고로 ECDSA에서 언급한 타원곡선 함수를 활용하는 방법도 있다.
여력이 되면 추가 정리하겠다.
RSA 추가 - Nonce
중간자 공격을 막는 방법은 임의의 난수(Nonce)를 만드는 것이다. 일단 서로 공개키를 알고 있다고 가정한다. 어차피 공개키는 막 뿌릴 수 있는 거라 어떻게든 서로의 것만 알면 된다. (참고로 서로 간 검증이 필요한 경우에 이렇게 하는 것이고, 그냥 서버만 공개키가 있어도 다를 건 없다.) 이제 이 공개키는 상대만 읽을 수 있으므로, 난수를 공개키로 암호화해서 보내는 것이다. 그리고 서로가 그렇게 난수를 주고 받으며 난수가 제대로 돌아왔는지 체크가 완료되면 대칭키를 만들어 보내는 방식. 공개키로 암호화된 난수는 중간에 해커가 있더라도 뜯어볼 수 없기 때문에 위변조가 불가능하다. 즉, 공개키를 이용해 상대가 내가 통신하고자 하는 상대가 맞다는 것을 검증할 수 있는 것이다!이 방식은 충분히 효과적이기에 이를 더 심화시키는 여러 바리에이션이 있다.
그러나 당장은 몇 가지 아쉬운 지점이 있다.
- 여러 서버와 여러 클라가 통신하는 상황에서, 각 주체는 통신하는 대상과 전부 알아서 대칭키를 만든다.
- 대칭키를 지나치게 많이 만드는 것도 궁극적으로는 보안 위협을 높일 수 있고, 비효율적이다.
- 대칭키의 만료 시간도 정할 수 없다.
- 아래에서 볼 무결성을 보장하기 힘들다.
- 전송 간 데이터 손실, 에러 가능성을 보장해줄 수 없다.
- 추가적으로, 공개키를 가지는 것만으로는 상대의 신원을 검증할 수 없다.
- 막말로 서버라 생각한 공개키가 해커의 것이라면 어떡할 것인가?
여기에서 굳이 다른 단점까지 거들먹거리는 이유는, 결국 이 방식이 오늘날 많이 사용되고 있기 때문이다.
아래에서 볼 실제 프로토콜들에서도 궁극적으로는 RSA를 심화시킨 방식을 많이 사용한다.
KDC 이용(Kerberos 프로토콜)
통신 주체 간 대칭키를 직접 관리하는 지점을 개선하는 것이 Key Distribution Center를 이용하는 것이다.
KDC는 보안 책임 주체인 제 3자로서, 서버와 클라가 연결될 때 단기간 사용할 세션키를 분배하는 역할을 한다.
이때 사용되는 프로토콜을 Kerberos 프로토콜이라고 부른다.[^8]
(한글로는 가장 잘 정리하신 듯[^7])
케르베로스 프로토콜은 인터넷 환경에서는 거의 사용되지 않는데, 그 이유는 프로토콜 자체를 설명한 이후에 부가하겠다.
과정을 설명하기에 앞서, KDC는 구체적으로 Authentication Server, Ticket Granting Server으로 나뉜다는 것을 잠시 짚겠다.
AS는 클라를 인증하는 역할을 하며, TGS가 실세 서버와 연결될 때 사용할 세션키를 발급하는 서버이다.
대부분의 설명이 이렇게 돼있어서 그것에 맞춰서 나도 설명은 하지만 원리를 이해하는데 있어서는 둘을 같은 것으로 봐도 전체 흐름을 깨진 않는 것 같다.
클라에 대한 정보를 가진 AS와 서버에 대한 정보를 가진 TGS를 합쳐서 KDC는 통신 주체들의 각 정보를 가지고 있다고 봐도 무방하다.
또 설명할 용어는 세션키이다.
이 프로토콜에서는 두 가지 방식으로 대칭키가 쓰인다.
하나는 통신을 할 때 사용되는 방식과, 서버가 검증용으로 내부적으로 사용하는 방식이다.
이중 통신을 할 때 사용하는 대칭키를 세션키라고 부른다.
당연하지만 세션키 자체를 보낼 때는 반드시 암호화되고, 또한 세션키는 수명을 가지고 있어서 시간이 지나면 만료된다.
혼선을 피하기 위해 이 둘을 명시적으로 분리해서 표기하겠다.
보통 세션키는 통신 주체를 둘다 명시해 표기하는데(클라/TGS 세션키) 나는 그렇게까지는 필요없다 생각해서 뺐다.
굳이? 싶은 용어가 많이 등장하기 때문에, 내 임의로 용어를 조금 바꾼 것들이 있다.
나는 키가 어떤 분류에 속하는지 초점을 두고 그림을 그렸다.
다른 글을 참고할 때는 이렇게 용어를 참고하면 된다.
Authenticator = (클라 ID + 타임스탬프)를 세션키로 암호화한 것으로, 인증에 사용된다.
티켓 = (클라 ID + 클라 IP 주소 + 타임스탬프 + 티켓 수명 + 세션키)로 이뤄진 데이터로, 항상 비밀키로 암호화된다.
TGT = Ticket Granting Ticket, 즉 티켓을 요청하는 티켓이다.
비밀키 = 이 문서에서 말하는 대칭키.(공개/비밀키할 때 용어랑 혼선이 있다 생각해서 나는 그냥 대칭키라 부른다)
이 프로토콜은 크게 두 과정을 거친다.
클라가 인증 서버로부터 인증을 받은 후 실제 통신하고자 하는 서버에 대한 입장권(티켓)을 얻는 과정과, 실제 그 티켓으로 서버에 검증을 받아 통신을 하는 과정이다.
클라 인증 및 서버 세션키 발급
간략하게 요약하면, 클라는 자신의 정보로 인증서버로부터 자신은 뜯어보지도 못하는 티켓을 받고, 이 티켓으로 각종 인증을 수행한다는 것이 핵심. - 먼저 클라가 평문으로 자신의 ID를 입력해서 보낸다. - 인증 서버(AS)는 클라가 비번이 있어야만 풀 수 있는 암호문을 돌려보낸다. - 이때 같이 딸려가는 데이터(초록색)가 있는데, 이후 단계에서 쓰일 데이터이다. - 클라가 비번으로 암호문을 복호화하면, 티켓 서버(TGS)와 통신할 수 있는 세션키를 얻게 된다. - 그럼 이 세션키로 클라는 자신의 정보를 암호화해서 티켓 서버로 날린다. - 인증 서버가 딸려보내준 데이터와, 통신하고 싶은 서버 ID를 합쳐서 그대로 같이 보낸다. - 티켓 서버는 딸려들어온 데이터를 먼저 풀어본다. - 이 데이터는 자신의 대칭키로 암호화돼있기 때문에 풀어볼 수 있다. - 여기에서 클라가 암호화한 데이터를 복호화할 수 있는 세션키를 얻을 수 있다. - 그림에서 보다시피 클라 정보가 두번 들어오는 꼴인데, 이를 통해 티켓 서버는 클라를 검증한다. - 검증이 끝나고 티켓 서버는 클라가 서버와 통신할 세션키를 만들고, 클라가 보낸 세션키로 암호화해 보낸다. - 그리고 서버 대칭키를 이용해 서버에서 인증할 때 사용할 데이터(주황색)를 딸려보낸다.클라는 자신은 뜯어보지도 못할 데이터를 두 번이나 받고 있는 게 보일 것이다.
인증 서버만이 클라의 비번을 알기 때문에, 다른 서버들이 클라를 인증할 수단이 필요하고 이를 위한 데이터가 보내지는 것이다.
최소한 다른 서버들은 인증 서버로부터 발급받은 데이터임을 확인할 수 있으니, 클라가 인증을 받았다고 믿을 수 있다.
그래서 이걸 흔히 티켓이라고 부른다.
클라 서버 통신
이제 서버와 통신할 세션키를 가진 클라는 서버에게 요청을 날리면 된다! - 클라는 티켓 서버한테 받았던 딸려온 데이터와, 서버 세션키로 자신의 정보를 담아서 서버에게 보낸다. - 서버는 티켓 서버가 그러했듯 딸려온 데이터를 풀어보고, 거기서 나온 서버 세션키로 클라 정보를 찾아낸다. - 이번에도 클라 정보는 교차 확인된다. - 검증 후 서버는 서버 세션키로 암호화돼있던 타임스탬프 값을 다시 서버 세션키로 암호화해서 클라에게 보낸다. - 이 과정은 프로토콜 5버전부터는 안 쓴다는 듯 - 클라는 이걸 뜯어서 자신이 보냈던 시점의 타임스탬프와 비교해본다. - 이걸 통해 클라 역시 서버를 검증한다. - 이제 서버 세션키로 해피 통신!검증 매커니즘은 결국 똑같다.
결국 요점은, KDC가 인증을 해주고 클라는 자신도 모르는 티켓을 받아서는 매번 들이밀며 자신이 인증됐다고 하는 것이다.
그리고 그 티켓 속에는 클라와 단 둘이 아는 세션키가 들어있어서 클라와 비밀 통신이 가능해진다.
특징과 한계
케르베로스 프로토콜은 LAN을 구성하고 있는 환경에서 통신할 때 쓰이곤 한다.
확실하게 안전한 통신이 가능하기 때문이다.
반면 더 넓은 범위의 네트워크에서는 거의 쓰이지 않는데, 케르베로스가 가진 한계 때문에 그렇다.
- 중앙 KDC가 단일 장애 지점(SPOF)이다.
- 인증과 키 생성까지 모든 책임을 KDC에서 지고 있기 때문에 이 친구가 무너지면 모든 통신이 마비되는 것과 다름없다.
- 또 KDC는 클라와 서버의 모든 정보를 쥐고 있기 때문에 이거 하나 털리면 끝장나는 거다..
- 시간에 대해 엄격하다.
- 주고받는 데이터에 시간을 엄밀하게 검사하는데, 시간 동기화가 조금이라도 안 돼있거나 오랜 지연이 발생할 경우 인증이 거부된다.
- 모든 클라와 서버가 고유한 네트워크 상의 이름(호스트)를 가져야 하기에 가상 호스팅과 클러스터 운영이 어렵다.
이렇듯 케르베로스를 통해 전송 암호화 뿐 아니라 신원 검증까지 확실하게 할 수 있음에도, 인터넷 환경에서는 다른 수단을 많이 활용하게 된다.
무결성
잠시 원점으로 돌아와서, 두번째 조건이었던 데이터 위변조 방지에 대한 방법들을 알아보자.
전송 간 암호화를 달성한다고 한다고 해서 데이터가 위조되지 않았다고 보장할 수는 없다.
서버와 클라 간에 통신이 여자저차 암호화됐어도, 데이터가 오고 가는 과정에서 데이터가 변질되지 않게, 서로가 명확하게 의도한 대로 전달됐음을 보장하기 위한 수단이 추가적으로 필요하다.
이를 위해 요구되는 속성이 바로 무결성으로, 무결성이란 말 그대로 데이터가 일관되고 신뢰성이 있어야 한다는 것이다.
해시
위에서 살펴본 해시는 데이터의 위변조를 방지할 수 있는 확실한 특징을 가지고 있다.
가령 서버에서 a라는 데이터를 보낼 때, 이 데이터를 해싱을 한번 한 후에 그 다이제스트를 같이 보낸다고 쳐보자.
그렇다면 클라는 a를 받은 이후에 서버가 사용한 해시 함수를 그대로 적용하여 같은 값이 나오는지 보고, 데이터가 변조되지 않았다고 확인할 수 있다.
하지만 당연히 이 방식은 신원 검증이 불가능하다.
게다가 이건 받은 데이터의 무결성만을 체크할 뿐이다.
서버의 응답을 해커가 완전히 가로채 b라는 데이터를 보내면서 이에 대한 다이제스트를 같이 보내버리면, 클라 입장에서는 변조됐다는 사실조차 알 수 없다.
MAC
Message Authentication Code는 대칭키를 이용해 위변조를 막는 방법이다.[^10]
해시에서 다이제스트를 붙여서 데이터를 보내듯이, 대칭키를 이용해 메시지 인증 코드(MAC)를 만든 뒤 그걸 데이터에 붙여 보낸다.
(속도만 빼고 해시 상위호환..)
서버가 a라는 데이터를 대칭키로 암호화한 값과 평문을 같이 보낸다면 같은 대칭키를 가지고 있는 클라는 암호문을 복호화 하여 데이터가 변조됐는지 체크할 수 있다.
MAC은 다양한 다른 암호화 방식과 결합되어 분화된다.
MAC 방식은 신뢰되는 대칭키를 가진 상대를 신뢰할 수 있다는 장점이 있다는 점에서, 일반 해시보다 훨씬 안전한 알고리즘이다.
그러나 해시와 마찬가지로 일단 기본 평문을 보내도록 설계돼있기에, 이 방식 자체로는 평문에 대한 아쉬움이 있다.
그래서 [[#전송 간 암호화]]에서 다룬 알고리즘과 혼합하여, 평문 자체는 암호화를 시키고 이를 복호화한 후 무결성을 검증하는 식으로 많이 활용된다.
무결성의 한계
PKI의 요구사항 중 마지막, 신원 검증이 왜 필요한지를 알아보기 위해 잠시 여기에서 무결성만 추구하는 할 때 발생하는 문제를 짚어본다.
언뜻 보면 MAC 방식은 서버와 클라만이 가진 대칭키를 이용한다는 점에서, 대칭키로 암호화됐다는 것만으로 상대의 신원이 어느 정도 보장되는 것이 아닌가 하는 생각이 들 수 있다.
그러나 여기에는 부인 봉쇄(non-repudiation)를 하지 못한다는 치명적인 문제가 발생한다.
부인 봉쇄란 통신 간 주체가 상대의 메시지를 부인하는 상황을 막는 것을 이야기한다.
가령 서버가 b라고 데이터를 보냈다고 해보자.
이때 클라는 b를 받고, 이를 대칭키로 무결성까지 검증했다.
그러나 이걸 받은 클라는 a를 받았다고 스스로 위변조를 한 다음에 대칭키로 MAC을 만들어 a에 대한 무결성도 마쳤다고 서버한테 큰소리를 칠 수 있다..
클라 역시 대칭키를 가지고 있으니, MAC을 만드는 방법을 알고 있기에 가능한 상황인 것이다.
그럼 반대로 서버는 어떨까?
반대로 서버도 클라가 이런 식으로 자신 마음대로 데이터를 위변조할 수 있다는 상황 때문에 클라가 보내오는 데이터를 믿지 못한답시고 부인할 가능성이 있다.
즉 통신 주체 간 믿을 수 없는 상황이 만들어질 여지를 막아야 하기 때문에 바로 부인 봉쇄가 필요한 것이다.
부인 봉쇄가 이뤄지지 않으면, 서로 속고 속이는 관계 속에서 데이터의 신뢰성을 확보할 수 없어 무결성을 확보했다고 할 수 없다.
그래서 엄밀한 차원에서, 무결성은 서로가 믿을 수 있는 상대라는, 신원 검증이라는 하나의 큰 속성을 추가적으로 만족해야만 하는 것이다.
무결성을 어떻게 정의하냐에 따라 다르겠지만, 나는 무결성이 신뢰성을 포함하는 개념이라고 생각한다.
그러면에서는 부인을 할 수 있는 가능성 역시 신뢰성을 떨어뜨리는 요건이라고 생각한다.
다만 전문적인 자료에서는 부인 방지 역시 큰 틀에서 무결성과 따로 보안의 한 요소로서 보는 것 같다.[^9]
신원 검증
무결성의 하위 탭으로 들어갈 수도 있다고 생각하지만, 이를 위한 방법론들을 조금 더 크게 다루기 위해 신원 검증은 별도로 큰 단락에서 다룬다.
RSA 디지털 서명
디지털 서명은 윗단락에서 다룬 무결성을 충족하는 방법 중 하나이다.
(참고로 디지털 서명에는 ElGamal, DSA 등의 다른 방법들도 있다.)
RSA 디지털 서명은 여태 소개한 방식들 중에서는 무결성을 검증하는 가장 좋은 방법이라고 할 수 있다.
(ECDSA, AEAD가 더 좋다는 글도 본 것 같긴 한데 암튼..)
개인키로만 서명이 가능하기 때문에, 클라 측에서 마음대로 조작을 할 수 없으니 부인 봉쇄까지 완료된다.
이를 통해 명확하게 상대를 신뢰할 수 있는 발판이 생기는 것이다!
중간 정리
지금까지 전송 간 암호화, 무결성을 달성할 수 있는 각종 방법들을 알아봤다.
이들을 조합하면 일차적으로 서버와 클라가 안전하게 통신할 수 있는 토대가 마련된다.
그러나 아직도 해결해야 할 문제가 하나 남았는데, 그것은 서버의 공개키를 믿는 과정이다.
RSA 디지털 서명으로 신원 검증이 달성된다고 이야기했지만, 사실 디지털 서명은 각 주체만이 서명을 할 수 있다는 점에서 서명자가 특정되니 검증된다고 하는 것이다.
그런데 만약에 클라가 접촉하려는 서버가 알고보니 악의적인 무언가였다면?
지금까지 이야기 나온 것들은 그저 서버가 공개키를 클라에게 주었을 때 이를 기반으로 서로가 안전하게 통신을 하는 방법에 대한 이야기이다.
하지만 공개키야 당장 나도 만들어서 뿌릴 수 있고 너도 뿌리고 피아노 위에서 탭댄스를 추는 원숭이도 뿌릴 수 있는 것이다.
즉, 정말로 상대에게서 공개키를 받았을 때 이 공개키가, 이 공개키를 가진 상대가 신뢰할 수 있는 대상인가를 믿을 만한 추가적인 지지 기반이 필요하다.
[[#KDC 이용(Kerberos 프로토콜)]]에서 본 방식을 이용할 수 있는가?
그 방식은 작은 네트워크 환경에서는 적합할지라도 단일 장애 지점이 존재한다는 것이 매우 큰 문제로 작용한다.
공개키 신뢰 방법
CA
그래서 Certifate Authority(CA)가 탄생했다.
KDC 만큼 막강한 능력들을 가진 것은 아니지만, 최소한 인터넷 환경에서 신뢰할 수 있는 공개키를 가진 인증 기관이다.
즉 CA의 공개키는 무조건 믿을 수 있다고 전세계적으로 합의가 되어 있고, 실제로 모든 기기에 기본적인 CA의 공개키가 저장돼있다.
(엄밀하게는 공개키를 포함하고 있는 인증서인데, 아래에서 보겠다.)
전세계에서 인정된 특정 기관들이 CA로서 지정되어 모든 통신에서 신뢰의 기반을 형성할 수 있도록 해준다.
이를 통해 인터넷 환경에서는 신뢰 관계를 넓힐 토대가 마련되는데, 바로 인증서(certificate)를 이용하는 것이다.
위의 RSA 디지털 서명은 통신에 있어서 무결성을 검증하기 위해 활용되기도 하지만, 무결성과 상대 신원을 검증할 수 있다는 특성 상 다른 용도로도 활용될 수 있다.
아주 간단한 발상이다.
- CA는 신뢰할 수 있다.
- 그렇다면 CA가 신뢰해주는 서버가 있다면?
- 해당 서버도 신뢰할 수 있다!
클라가 서버를 신뢰할 수 있게 되는 흐름을 조금 더 구체화시키면 이렇게 된다.
- CA가 어떤 서버의 공개키에 대해 CA의 개인키로 암호화해준다.
- CA가 암호화해줬다, 즉 디지털 서명을 해주었다 하여 인증서라고 부른다.
- 클라는 CA의 공개키를 가지고 있으니 해당 암호문을 복호화할 수 있다.
- CA에게 서명을 받은 서버의 공개키이니, 이 공개키는 신뢰할 수 있다!
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 - 인증 기관의 디지털 서명 값이 담긴다.
공개키와, 공개키의 소유 주체가 일단 담겨져 있다.
그리고 이 공개키를 인증하기 위한 발행자(인증 기관)가 누군지, 이 발행자가 서명한 내용도 담겨있다.
이 인증서를 받은 클라는 일단 내용을 확인해, 발행자의 정보를 읽고 발행자의 공개키를 통해 디지털 서명 부분을 복호화하여 이 인증서가 정말 유효한지 검증한다.
검증이 되면, 이제 이 공개키를 누가 가지고 있는지, 누가 서명해줬는지가 확실하게 판명난다.
> [!NOTE] CA도 인증서가 있다.
> 인증서의 형식을 보면 알겠지만, 인증서에는 단순하게 공개키 뿐만 아니라 공개키의 주체의 정보도 담긴다.
> 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
드디어 이 문서의 핵심, PKI가 등장한 이유가 성립됐다.
여태 보았듯이 결국 인터넷 환경에서 안전한 통신을 위해서는 공개키 자체를 신뢰할 수 있는 인프라가 구성돼야 한다는 것을 알 수 있다.
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는 웹 환경에서 도메인을 가진 서버에서 쓰일 인증서를 발급하는 프로토콜이다.[^15]
이 프로토콜은 정해진 규격에만 따르면 서버 신원 검증, 인증서 발급 및 갱신까지도 자동화한다.
> [!NOTE] 다른 방법?
> 해당 RFC8555에 따르면, 보통의 인증서 발행 흐름은 다음과 같았다.
> - 서버에서 자신의 도메인을 담은 CSR 생성
> - CA 웹 페이지에 복붙
> - CA는 도메인 소유권을 검증하기 위해 몇 가지 방법 제공
> - CA에서 제시한 웹 사이트 챌린지 성공(그냥 html 태그를 헤더에 넣으라 이런 거)
> - CA에서 제시한 도메인 챌린지 성공(TXT 레코드에 어떤 값 넣기)
> - CA에서 제시한 이메일 챌린지 성공(도메인 이메일로 전달된 내용을 CA에게 재전달)
> - 검증 완료 후 CA에서 발행한 인증서를 다운로드
>
> 이 과정이 수동으로 이뤄지기에, 인증서 발급 과정은 매우 귀찮은 일이고 추가적으로 갱신 시에도 비슷한 짓을 반복해야 한다.
> 그래서 나온 프로토콜이 ACME이다.
ACME에서는 일단 서버는 CA에 계정을 등록해야 한다.
(더 엄밀하게는 CA로부터 인증서를 받아주고 서버의 신원을 먼저 검증하는 앞단인 Registration Authority가 있을 수 있다.)
<div id="Drawing_2025-03-11_1231.55.excalidraw.md11"></div><script>(function(){const InitialData={"type":"excalidraw","version":2,"source":"https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/2.8.2","elements":[{"id":"7ScVp6e3oaPHdkB-KxQi6","type":"rectangle","x":-373.3927307128906,"y":-495.5988531716408,"width":130.54052734375,"height":78.50689697265625,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a2","roundness":{"type":3},"seed":1681111447,"version":84,"versionNonce":165924727,"isDeleted":false,"boundElements":[{"id":"vq9jYxqsh_E80nKv4LeLT","type":"arrow"},{"type":"text","id":"30uHhT2K"}],"updated":1741663927963,"link":null,"locked":false},{"id":"30uHhT2K","type":"text","x":-326.3424530029297,"y":-468.8454046853127,"width":36.439971923828125,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a3","roundness":null,"seed":694551193,"version":22,"versionNonce":1047058393,"isDeleted":false,"boundElements":null,"updated":1741665404450,"link":null,"locked":false,"text":"서버","rawText":"서버","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"7ScVp6e3oaPHdkB-KxQi6","originalText":"서버","autoResize":true,"lineHeight":1.25},{"id":"auJlpzqM-Sae94PFnxEdY","type":"rectangle","x":15.033843994140625,"y":-496.5117560036721,"width":130.54052734375,"height":78.50689697265625,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a4","roundness":{"type":3},"seed":564494295,"version":120,"versionNonce":809231511,"isDeleted":false,"boundElements":[{"type":"text","id":"jsKRQnAf"},{"id":"ttLMl9E5KqNtnWVpzWAc-","type":"arrow"}],"updated":1741663920310,"link":null,"locked":false},{"id":"jsKRQnAf","type":"text","x":67.55412292480469,"y":-469.75830751734395,"width":25.499969482421875,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a5","roundness":null,"seed":313879799,"version":77,"versionNonce":699668055,"isDeleted":false,"boundElements":[],"updated":1741664774199,"link":null,"locked":false,"text":"CA","rawText":"CA","fontSize":20,"fontFamily":5,"textAlign":"center","verticalAlign":"middle","containerId":"auJlpzqM-Sae94PFnxEdY","originalText":"CA","autoResize":true,"lineHeight":1.25},{"id":"vq9jYxqsh_E80nKv4LeLT","type":"arrow","x":-313.14321899414057,"y":-407.47129172485074,"width":0,"height":609.6754430229366,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a6","roundness":{"type":2},"seed":1904915991,"version":349,"versionNonce":1809287735,"isDeleted":false,"boundElements":[],"updated":1741674830398,"link":null,"locked":false,"points":[[0,0],[0,609.6754430229366]],"lastCommittedPoint":null,"startBinding":{"elementId":"7ScVp6e3oaPHdkB-KxQi6","focus":0.07692250146812857,"gap":9.620664474133832,"fixedPoint":null},"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"ttLMl9E5KqNtnWVpzWAc-","type":"arrow","x":83.95559692382812,"y":-411.50649492292956,"width":0,"height":618.5958474553468,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a7","roundness":{"type":2},"seed":354016055,"version":205,"versionNonce":413537879,"isDeleted":false,"boundElements":[],"updated":1741674833005,"link":null,"locked":false,"points":[[0,0],[0,618.5958474553468]],"lastCommittedPoint":null,"startBinding":{"elementId":"auJlpzqM-Sae94PFnxEdY","focus":-0.05594414749370668,"gap":6.498364108086264,"fixedPoint":null},"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"6tNf4nMAjBaCao4aQ6kWH","type":"arrow","x":-304.50792072705815,"y":-183.51298046442628,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"a9","roundness":{"type":2},"seed":996653431,"version":160,"versionNonce":1478625719,"isDeleted":false,"boundElements":[],"updated":1741672711267,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"SfR7tdhw1LS5EYXyWb5q3","type":"arrow","x":-311.7110477091415,"y":-384.83354154715096,"width":393.2580188901302,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aO","roundness":{"type":2},"seed":953916087,"version":103,"versionNonce":1003538103,"isDeleted":false,"boundElements":null,"updated":1741669734682,"link":null,"locked":false,"points":[[0,0],[393.2580188901302,0]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"WVUzMbec","type":"text","x":-406.2144514687328,"y":-554.3933814308243,"width":190.05987548828125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aS","roundness":null,"seed":1805311353,"version":89,"versionNonce":265096535,"isDeleted":false,"boundElements":null,"updated":1741670237636,"link":null,"locked":false,"text":"계정 이미 등록한 상태","rawText":"계정 이미 등록한 상태","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"계정 이미 등록한 상태","autoResize":true,"lineHeight":1.25},{"id":"CHqk1l4z","type":"text","x":-224.3831013838564,"y":-412.5055154028634,"width":217.8998260498047,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aT","roundness":null,"seed":247355863,"version":102,"versionNonce":2050170775,"isDeleted":false,"boundElements":null,"updated":1741671117857,"link":null,"locked":false,"text":"인증서 발행 주문(Order)","rawText":"인증서 발행 주문(Order)","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"인증서 발행 주문(Order)","autoResize":true,"lineHeight":1.25},{"id":"puQxB08d","type":"text","x":91.10060199724722,"y":-150.34052298558066,"width":144.4398956298828,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aU","roundness":null,"seed":1652458457,"version":253,"versionNonce":1041086009,"isDeleted":false,"boundElements":null,"updated":1741673596776,"link":null,"locked":false,"text":"챌린지 검사 시작","rawText":"챌린지 검사 시작","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"챌린지 검사 시작","autoResize":true,"lineHeight":1.25},{"id":"Ew6Ul8JH","type":"text","x":-425.5697593177692,"y":-239.42550644120212,"width":99.919921875,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aV","roundness":null,"seed":1825535353,"version":62,"versionNonce":2111867417,"isDeleted":false,"boundElements":null,"updated":1741672690483,"link":null,"locked":false,"text":"챌린지 수행","rawText":"챌린지 수행","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"챌린지 수행","autoResize":true,"lineHeight":1.25},{"id":"Id8tUixN","type":"text","x":-303.92381733919484,"y":-19.507072176745964,"width":380.75970458984375,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aY","roundness":null,"seed":288780889,"version":379,"versionNonce":2027969049,"isDeleted":false,"boundElements":null,"updated":1741673704841,"link":null,"locked":false,"text":"CSR(DER형식)을 담아 finlaizeURL로 전송","rawText":"CSR(DER형식)을 담아 finlaizeURL로 전송","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"CSR(DER형식)을 담아 finlaizeURL로 전송","autoResize":true,"lineHeight":1.25},{"id":"Vy1wQhSb","type":"text","x":92.10906379051437,"y":13.142266250194155,"width":101.15994262695312,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aZ","roundness":null,"seed":2050883865,"version":174,"versionNonce":382113145,"isDeleted":false,"boundElements":null,"updated":1741677115072,"link":null,"locked":false,"text":"인증서 발행","rawText":"인증서 발행","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"인증서 발행","autoResize":true,"lineHeight":1.25},{"id":"3aHSBGSC","type":"text","x":-171.81864313211418,"y":112.67415175369206,"width":100.99993896484375,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aa","roundness":null,"seed":9508887,"version":129,"versionNonce":654786617,"isDeleted":false,"boundElements":null,"updated":1741677090974,"link":null,"locked":false,"text":"인증서 내놔","rawText":"인증서 내놔","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"인증서 내놔","autoResize":true,"lineHeight":1.25},{"id":"lNwE5zpp","type":"text","x":-441.97562263459463,"y":-524.4075139498393,"width":429.61962890625,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ac","roundness":null,"seed":473482551,"version":188,"versionNonce":209344953,"isDeleted":false,"boundElements":null,"updated":1741674888120,"link":null,"locked":false,"text":"모든 요청에는 JWS kid 헤더값이 들어가있어야 함","rawText":"모든 요청에는 JWS kid 헤더값이 들어가있어야 함","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"모든 요청에는 JWS kid 헤더값이 들어가있어야 함","autoResize":true,"lineHeight":1.25},{"id":"gsKTS8Ck","type":"text","x":-280.90536827979366,"y":-375.35008378042215,"width":300.4397888183594,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ad","roundness":null,"seed":579593527,"version":458,"versionNonce":612887161,"isDeleted":false,"boundElements":[],"updated":1741673711169,"link":null,"locked":false,"text":"201: finalizeURL, 인가 검증 URL","rawText":"201: finalizeURL, 인가 검증 URL","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"201: finalizeURL, 인가 검증 URL","autoResize":true,"lineHeight":1.25},{"id":"PMuHLrus","type":"text","x":91.83183886839703,"y":-52.34864438006804,"width":121.13990783691406,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ae","roundness":null,"seed":307235191,"version":139,"versionNonce":399681817,"isDeleted":false,"boundElements":null,"updated":1741673926399,"link":null,"locked":false,"text":"Order: ready","rawText":"Order: ready","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Order: ready","autoResize":true,"lineHeight":1.25},{"id":"BYcIon4o","type":"text","x":95.55125282592343,"y":-374.57012461151766,"width":138.5398712158203,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"af","roundness":null,"seed":602197977,"version":28,"versionNonce":957190199,"isDeleted":false,"boundElements":null,"updated":1741673719773,"link":null,"locked":false,"text":"Order: pending","rawText":"Order: pending","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Order: pending","autoResize":true,"lineHeight":1.25},{"id":"hi5O5Q-Rum0nWugbSBsM_","type":"arrow","x":-308.44875803103673,"y":-284.7057518161908,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ag","roundness":{"type":2},"seed":1719036281,"version":187,"versionNonce":1349593657,"isDeleted":false,"boundElements":[],"updated":1741672088093,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"p1kreG3F","type":"text","x":-218.26153415666272,"y":-310.8964730202993,"width":185.119873046875,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ah","roundness":null,"seed":59320343,"version":80,"versionNonce":136638105,"isDeleted":false,"boundElements":null,"updated":1741673700952,"link":null,"locked":false,"text":"인가 검증URL로 요청","rawText":"인가 검증URL로 요청","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"인가 검증URL로 요청","autoResize":true,"lineHeight":1.25},{"id":"UlmDr0fi","type":"text","x":-253.6677703216012,"y":-274.3652779912387,"width":302.3997497558594,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ai","roundness":null,"seed":194336919,"version":115,"versionNonce":941413783,"isDeleted":false,"boundElements":null,"updated":1741673711169,"link":null,"locked":false,"text":"200: 챌린지 유형과 체크요청 URL","rawText":"200: 챌린지 유형과 체크요청 URL","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"200: 챌린지 유형과 체크요청 URL","autoResize":true,"lineHeight":1.25},{"id":"vXYjTDYmqAFilrVVLluih","type":"arrow","x":-309.26293101781675,"y":-74.64234371041823,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aj","roundness":{"type":2},"seed":1174973913,"version":242,"versionNonce":1361739769,"isDeleted":false,"boundElements":[],"updated":1741673537110,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"HWXqAMqY","type":"text","x":-229.37595353296211,"y":-211.0202134652924,"width":248.41976928710938,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"al","roundness":null,"seed":1592308919,"version":76,"versionNonce":1977883799,"isDeleted":false,"boundElements":null,"updated":1741673702202,"link":null,"locked":false,"text":"챌린지 체크요청 URL로 요청","rawText":"챌린지 체크요청 URL로 요청","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"챌린지 체크요청 URL로 요청","autoResize":true,"lineHeight":1.25},{"id":"Sap1x4HQ","type":"text","x":92.88296481531279,"y":-320.79858834023,"width":130.7598876953125,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"am","roundness":null,"seed":211090167,"version":67,"versionNonce":1721566935,"isDeleted":false,"boundElements":[],"updated":1741673730255,"link":null,"locked":false,"text":"Auth: pending","rawText":"Auth: pending","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Auth: pending","autoResize":true,"lineHeight":1.25},{"id":"2GnHu9Rh","type":"text","x":-230.31566027927136,"y":-106.00801178419789,"width":238.15985107421875,"height":25,"angle":0,"strokeColor":"#1971c2","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ap","roundness":null,"seed":1167085529,"version":178,"versionNonce":2145365753,"isDeleted":false,"boundElements":null,"updated":1741673704841,"link":null,"locked":false,"text":"인가 검증 URL로 상태 확인","rawText":"인가 검증 URL로 상태 확인","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"인가 검증 URL로 상태 확인","autoResize":true,"lineHeight":1.25},{"id":"I1AZKwpb","type":"text","x":-148.66966805235313,"y":-177.66100503650648,"width":40.55995178222656,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aq","roundness":null,"seed":1090417817,"version":43,"versionNonce":83243865,"isDeleted":false,"boundElements":null,"updated":1741673711169,"link":null,"locked":false,"text":"200","rawText":"200","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"200","autoResize":true,"lineHeight":1.25},{"id":"eKd9kJLo","type":"text","x":94.33011098792474,"y":-115.62046312561432,"width":103.05990600585938,"height":25,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ar","roundness":null,"seed":1839846743,"version":131,"versionNonce":1826194007,"isDeleted":false,"boundElements":[],"updated":1741673599126,"link":null,"locked":false,"text":"Auth: valid","rawText":"Auth: valid","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"Auth: valid","autoResize":true,"lineHeight":1.25},{"id":"AqAMT_OMKvsYhw_griuMc","type":"arrow","x":-309.6388473756119,"y":11.89786862218881,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"au","roundness":{"type":2},"seed":1440743577,"version":248,"versionNonce":1013940473,"isDeleted":false,"boundElements":[],"updated":1741673553077,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"Ln95q78k","type":"text","x":-141.15288508801808,"y":-70.99737571921457,"width":40.55995178222656,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"av","roundness":null,"seed":255602969,"version":40,"versionNonce":322702007,"isDeleted":false,"boundElements":null,"updated":1741673711169,"link":null,"locked":false,"text":"200","rawText":"200","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"200","autoResize":true,"lineHeight":1.25},{"id":"cnCrlAuj","type":"text","x":-234.28713500833737,"y":44.776732431122696,"width":239.13983154296875,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aw","roundness":null,"seed":197394423,"version":143,"versionNonce":941959065,"isDeleted":false,"boundElements":[],"updated":1741677117622,"link":null,"locked":false,"text":"200: 인증서 다운로드 URL","rawText":"200: 인증서 다운로드 URL","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"200: 인증서 다운로드 URL","autoResize":true,"lineHeight":1.25},{"id":"OKGVTC3gBXZZq7WaT3ee0","type":"arrow","x":-305.5978330533061,"y":145.2446268491176,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ax","roundness":{"type":2},"seed":2025710231,"version":300,"versionNonce":814010649,"isDeleted":false,"boundElements":[],"updated":1741677090974,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"36nc4QBo","type":"text","x":-168.8657417942975,"y":154.00065746182713,"width":87.27992248535156,"height":25,"angle":0,"strokeColor":"#2f9e44","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"ay","roundness":null,"seed":631590103,"version":46,"versionNonce":1507673593,"isDeleted":false,"boundElements":null,"updated":1741677090974,"link":null,"locked":false,"text":"200: ㅇㅇ","rawText":"200: ㅇㅇ","fontSize":20,"fontFamily":5,"textAlign":"left","verticalAlign":"top","containerId":null,"originalText":"200: ㅇㅇ","autoResize":true,"lineHeight":1.25},{"id":"Rt9tSzgLcSkKuMNrcPrGv","type":"arrow","x":81.54678064839516,"y":36.92175005572528,"width":393.25807332801384,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"b00","roundness":{"type":2},"seed":682762745,"version":55,"versionNonce":288653945,"isDeleted":false,"boundElements":null,"updated":1741677110611,"link":null,"locked":false,"points":[[0,0],[-393.25807332801384,0]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"jGaFU7Cm7nC9vPSr3W1Mu","type":"arrow","x":77.56552124023438,"y":148.20616736833267,"width":387.64822297581566,"height":0,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aB","roundness":{"type":2},"seed":1308821431,"version":260,"versionNonce":1126288471,"isDeleted":true,"boundElements":[],"updated":1741673675828,"link":null,"locked":false,"points":[[0,0],[-387.64822297581566,0]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"55VEEXfeM-6zaNhVja8U_","type":"arrow","x":77.66802789438884,"y":117.07694785860645,"width":387.93292821525824,"height":0.8880250111953387,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"aI","roundness":{"type":2},"seed":675425175,"version":196,"versionNonce":2061314777,"isDeleted":true,"boundElements":[],"updated":1741673674554,"link":null,"locked":false,"points":[[0,0],[-387.93292821525824,-0.8880250111953387]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false},{"id":"3b9-OodEUl9ewgyNKkzqn","type":"arrow","x":-292.57079307540647,"y":28.000010525406807,"width":389.7958984375,"height":0.912841796875,"angle":0,"strokeColor":"#1e1e1e","backgroundColor":"transparent","fillStyle":"solid","strokeWidth":2,"strokeStyle":"solid","roughness":1,"opacity":100,"groupIds":[],"frameId":null,"index":"az","roundness":{"type":2},"seed":1615488023,"version":252,"versionNonce":1257474647,"isDeleted":true,"boundElements":[],"updated":1741677096431,"link":null,"locked":false,"points":[[0,0],[389.7958984375,-0.912841796875]],"lastCommittedPoint":null,"startBinding":null,"endBinding":null,"startArrowhead":null,"endArrowhead":"arrow","elbowed":false}],"appState":{"theme":"dark","viewBackgroundColor":"#ffffff","currentItemStrokeColor":"#1e1e1e","currentItemBackgroundColor":"transparent","currentItemFillStyle":"solid","currentItemStrokeWidth":2,"currentItemStrokeStyle":"solid","currentItemRoughness":1,"currentItemOpacity":100,"currentItemFontFamily":5,"currentItemFontSize":20,"currentItemTextAlign":"left","currentItemStartArrowhead":null,"currentItemEndArrowhead":"arrow","currentItemArrowType":"round","scrollX":607.7743627513935,"scrollY":452.4118114527631,"zoom":{"value":1.121189},"currentItemRoundness":"round","gridSize":20,"gridStep":5,"gridModeEnabled":false,"gridColor":{"Bold":"rgba(217, 217, 217, 0.5)","Regular":"rgba(230, 230, 230, 0.5)"},"currentStrokeOptions":null,"frameRendering":{"enabled":true,"clip":true,"name":true,"outline":true},"objectsSnapModeEnabled":false,"activeTool":{"type":"selection","customType":null,"locked":false,"lastActiveTool":null}},"files":{}};InitialData.scrollToContent=true;App=()=>{const e=React.useRef(null),t=React.useRef(null),[n,i]=React.useState({width:void 0,height:void 0});return React.useEffect(()=>{i({width:t.current.getBoundingClientRect().width,height:t.current.getBoundingClientRect().height});const e=()=>{i({width:t.current.getBoundingClientRect().width,height:t.current.getBoundingClientRect().height})};return window.addEventListener("resize",e),()=>window.removeEventListener("resize",e)},[t]),React.createElement(React.Fragment,null,React.createElement("div",{className:"excalidraw-wrapper",ref:t},React.createElement(ExcalidrawLib.Excalidraw,{ref:e,width:n.width,height:n.height,initialData:InitialData,viewModeEnabled:!0,zenModeEnabled:!0,gridModeEnabled:!1})))},excalidrawWrapper=document.getElementById("Drawing_2025-03-11_1231.55.excalidraw.md11");ReactDOM.render(React.createElement(App),excalidrawWrapper);})();</script>
> [!NOTE] 그림 부언
> 다른 트래픽 그림들과 다르게, 이 프로토콜은 완벽하게 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
TLS는 PKI 시스템을 활용하는 가장 많이 알려진 보안 프로토콜 중 하나로, 실질적으로 이 문서에서 PKI를 설명하기 위해 활용한 전반적인 구조도 최종적으로는 TLS를 설명할 목적으로 작성됐다..
자세한 내용은 해당 문서로 옮겼다.
# 결론
이렇듯 PKI는 공개키를 신뢰할 수 있도록 하기 위해 고안된 시스템 구조이다.
이 시스템 덕분에, 전송 간 암호화를 보장하기 위해 비대칭키를 안전하게 활용할 수 있게 된다.
여기에 공개키를 이용한 디지털 서명의 검증과, 검증 체이닝을 통해 신원까지도 검증한다.

이를 기반으로 TLS가 성립하고, 여타 안전한 통신을 위한 다양한 프로토콜이 구현된다.[^13]
그래서 먼저 이게 PKI가 뭔지 이해하고, 다른 프로토콜들을 차근차근 이해해나가는 것이 중요하다고 생각한다.
# 여담
재밌긴 한데 힘들다..
암호학에 대해 제대로 공부해본 적이 없어 내용 정리를 하면서 많이 헤맸다.
지식이 점차 쌓여가니 정리 방향과 순서에 하자가 있다는 걸 깨달을 때가 있어서 몇 번 문서를 뜯어고쳤다.
그런데도 지금 다시 보니 또 아쉬운 정리가 돼버렸다.
대표적으로 무결성 검증 부분에서 그림은 틀리지 않았지만 설명의 흐름이 자연스럽게 디지털 서명으로 이어지지 않는다.
나중에 시간이 남는다면 총체적으로 디렉토리를 따로 파서 문서를 나누면 좋을 것 같다.

~~설마 내가 RFC 문서까지 직접 읽게 될 줄은 몰랐다~~
문서 읽다보니 재밌어서 시간 가는 줄 모르겠다..
꺼무위키 읽는 느낌이랄까
# 관련 문서
| 이름 | noteType | created |
| ---------------------------------------------------------------------------------------------------------------- | ------------- | ---------- |
| SSH 터널링 | \- | 2024-07-12 |
| Amazon Cognito | knowledge | 2024-07-04 |
| AWS Web Application Firewall | knowledge | 2024-07-04 |
| SSH | knowledge | 2024-07-13 |
| SockS | knowledge | 2024-07-13 |
| 쿠버 RBAC | knowledge | 2024-09-02 |
| code reuse attack | knowledge | 2024-06-20 |
| buffer overflow | knowledge | 2024-06-13 |
| TLS downgrade attack | knowledge | 2024-06-20 |
| sudo | knowledge | 2024-06-13 |
| Secret | knowledge | 2025-01-12 |
| 파드 시큐리티 스탠다드 | knowledge | 2025-01-13 |
| ServiceAccount | knowledge | 2025-01-13 |
| API 접근 제어 우회 | knowledge | 2025-01-13 |
| 멀티 테넌시 | knowledge | 2025-01-13 |
| Authentication | knowledge | 2025-01-13 |
| OIDC | knowledge | 2025-01-13 |
| 리눅스 커널 보안 제약 | knowledge | 2025-01-14 |
| 보안 체크리스트 | knowledge | 2025-01-14 |
| openssl | knowledge | 2025-01-18 |
| Authorization | knowledge | 2025-01-19 |
| RBAC | knowledge | 2025-01-19 |
| Admission Control | knowledge | 2025-01-20 |
| Admission Webhook | knowledge | 2025-01-20 |
| cfssl | knowledge | 2025-01-23 |
| Keycloak | knowledge | 2025-01-27 |
| AWS Identity and Access Management | knowledge | 2025-01-31 |
| PKI | knowledge | 2025-03-10 |
| Audit | knowledge | 2025-03-12 |
| 암호 알고리즘 총괄 | knowledge | 2025-03-15 |
| Cert Manager | knowledge | 2025-03-15 |
| Validation Admission Policy | knowledge | 2025-03-17 |
| Security | knowledge | 2025-04-11 |
| Shamir Secret Sharing | knowledge | 2025-04-11 |
| 볼트 in 쿠버네티스 | knowledge | 2025-04-14 |
| Vault Secret Operator | knowledge | 2025-04-14 |
| TLS | knowledge | 2025-04-16 |
| Istio PeerAuthentication | knowledge | 2025-05-04 |
| SPIFFE | knowledge | 2025-05-04 |
| Istio RequestAuthentication | knowledge | 2025-05-04 |
| Istio AuthorizationPolicy | knowledge | 2025-05-04 |
| JWT | knowledge | 2025-05-05 |
| OAuth | knowledge | 2025-05-09 |
| 나스 초기 세팅 | project | 2024-12-11 |
| 6W - PKI 구조, CSR 리소스를 통한 api 서버 조회 | published | 2025-03-15 |
| 6W - api 구조와 보안 1 - 인증 | published | 2025-03-15 |
| 6W - api 보안 2 - 인가, 어드미션 제어 | published | 2025-03-16 |
| 3W - Public Key Infrastructure | published | 2025-03-21 |
| 5W - 이스티오 mTLS와 SPIFFE | published | 2025-05-11 |
| 5W - 이스티오 JWT 인증 | published | 2025-05-11 |
| 5W - 이스티오 인가 정책 설정 | published | 2025-05-11 |
| E-로컬 ssh 서버 세팅 | topic/explain | 2024-07-13 |
| E-쿠버네티스 인증 실습 | topic/explain | 2025-01-21 |
| E-Kyverno 기본 실습 | topic/explain | 2025-03-17 |
| E-openssl을 이용한 인증서 생성 실습 | topic/explain | 2025-03-22 |
| T-각 네임스페이스 서비스 어카운트에 권한 바인딩 | topic/temp | 2025-03-16 |
| T-서비스 어카운트 토큰은 어떻게 인증되는가 | topic/temp | 2025-03-16 |
{ .block-language-dataview}
# 참고
[^5]: https://namu.wiki/w/RSA%20%EC%95%94%ED%98%B8%ED%99%94
[^7]: https://hyeo-noo.tistory.com/415
[^8]: https://en.wikipedia.org/wiki/Kerberos_(protocol)
[^9]: https://danyoujeong.tistory.com/222
[^10]: https://en.wikipedia.org/wiki/Message_authentication_code#An_example_of_MAC_use
[^11]: https://en.wikipedia.org/wiki/HMAC
[^12]: https://blog.humminglab.io/posts/tls-cryptography-7-diffie-hellman/
[^13]: https://en.wikipedia.org/wiki/Public_key_infrastructure#Uses
[^14]: https://en.wikipedia.org/wiki/X.509
[^15]: https://datatracker.ietf.org/doc/html/rfc8555
[^16]: https://datatracker.ietf.org/doc/html/rfc5246#autoid-32