간단한 Docs 서비스를 aws s3를 통해서 제공하고자 했는데 그 과정중에 SSL/TLS 인증서가 ACM을 통해서 어떻게 받아지고 관리되는지에 대한 이해가 부족해서 Cloudflare에 연결하는데 시간을 허비했다.
고쳐나가면서 필요했던 정보들을 기록하고 잊지말자!
s3 에는 static hosting 기능이 제공된다.
s3에 bucket을 만들고 bucket 의 properties 탭으로 들어가서 아래로 내려가다 보면 Static website hosting 이 있다.
Edit을 통해서 해당기능을 enable 시키게 되면 설정을 할 수 있는데 두 가지 호스팅 타입이 있다.
해당 블로그에서는 Host a static website만 기술하도록 하겠다.
Host a static website 타입을 선택하면 index document, error document, redirection rules 를 설정할 수 있다.
index document를 설정해서 endpoint를 통해서 사용자에게 보여줄 index.html 을 설정하면 된다. 해당 bucket에 있는 html 을 설정하면 되고 index 라는 명칭을 꼭 사용할 필요는 없다.
error document는 error 가 발생했을 때 보여줄 page 를 등록하는 것.
Redirection rules 는
[
{
"Condition": {
"HttpErrorCodeReturnedEquals": "string",
"KeyPrefixEquals": "string"
},
"Redirect": {
"HostName": "string",
"HttpRedirectCode": "string",
"Protocol": "http"|"https",
"ReplaceKeyPrefixWith": "string",
"ReplaceKeyWith": "string"
}
}
]
위와같이 특정 조건에 대해서 어떻게 redirect할지를 설정하는 기능이다.
설정을 완료하고 나면 object에 접근할 수 있는 권한을 부여해줘야한다.
Block public access 를 통해서 필요에 따른 access 정도를 설정할 수 있다. 완전 public 오픈을 하려면 모든 block을 off 하면 된다.
그후 Bucket policy를 설정해주면 된다.
AWS 에서 제공해주는 정책생성기를 사용해서 만들어도 좋고 docs 를 참고해서 만들어도 된다. 단순 read 권한만 주기 위해 아래와 같이 GetObject action만 추가하였다.
{
"Version": "2012-10-17",
"Id": "Policy1661773862871",
"Statement": [
{
"Sid": "Stmt1661773860570",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
이를 설정했으면 properties tap에서 제공되는 endpoint를 확인할 수 있다. 이를 통해서 접속이 가능하다. 하지만 s3 static website hosting은 SSL/TLS를 제공해주지는 않는다. (각 object에 대한 https 는 되는데 이건 안된다.) 따라서 추가적으로 CloudFront 혹은 Loadbalancer를 달아줘야한다. 하지만 굳이 Loadbalancer를 달아줄 필요는 없으니 CloudFront로 대체.
https 를 사용하기 위해서는 SSL 인증서가 필요하다 따라서 해당 인증서를 발급받아줘야한다. AWS에서는 ACM을 통해서 인증서 발급이 가능하다. AWS 자체에서 Route 53 을 통해 도메인 등록이 가능하지만 따로 외부 공급자 ( 고대디, 가비아, Cloudflare )를 사용한다면 해당 공급자에서 정보를 가져오게 된다.
ACM 을 통해서 인증서를 발급을 신청할 때 2 가지 옵션이 있는데
Email validation은 AWS에 등록된 이메일 계정을 통해서 인증을 하는 방식이다.
Dns validation 은 CA 의 CNAME record를 등록하여서 이를 통해서 검증을 하는 방식이다.
값을 모두 설정하고 요청을 날리게 되면 Certificate이 생성되고 다음과 같은 CNAME 값을 주게된다.
(Record value 값은 _424c7224e9b0146f9a8808af955727d0.acm-validations.aws.)
해당 값을 사용하고 있는 CA에 등록해주면 된다.
위 예는 Cloudflare이다. 위와 같이 등록을 해주면 인증서의 유효성검사가 통과되게 되고 ACM에서 CA의 인증서를 받아 관리를 할 수 있게 되는 것이다.
값을 등록할 때는 Domain Name, Record Name(Key), Record Type, Record Value(Value) 모두 정확하게 입력해줘야한다. 그래야 검사를 통과할 수 있음!
ACM 은 이 Key, Value 값을 Ownership 검사를 하게 되는데 같은 Key, Value를 사용하는 ACM이라면 같은 인증서라고 보면 된다.
이렇게 한 번 등록하고 나면 추가로 ACM을 발행할 때 따로 등록할 필요없이 바로바로 사용할 수 있어서 편리하다.
ACM 발급까지 끝났다면 CloudFront를 s3에 연결하면 된다. (부가적인 기능들은 생략하고 SSL 설정만 다루도록 하겠음 )
Origin domain으로 설정한 s3 static website 의 endpoint를 등록해주고 name을 정해준다. 추가로 Routing될 때 헤더값을 추가할 수 있는데 해당 설정이 필요하다면 추가하면 된다.
등록했던 SSL 인증서를 등록
생성을 하면 Domain name 및 기타 정보들이 제공된다.
해당 Domain name을 통해서 접속이 가능하며 이제 최종적으로 해당 값을 CA에 DNS Record를 등록하여 사용할 수 있게 된다.
Cloudflare에서는 인증서를 통해서 검증을 마친 request들만 pass를 시키고 있었는데 인증서 작업을 거치지 않은 static website를 연결하려고 하니 SSL handshake flaed 문제가 발생했었다.
SSL 이 일어나기 전에 TCP 3-way-handshake가 일어난다.
그 후에 아래와 같이 일련의 과정을 거치게 된다.
'ClientHello' 메시지: 클라이언트가 서버로 "헬로" 메시지를 전송하면서 핸드셰이크를 개시. 이 메시지에는 클라이언트가 지원하는 TLS 버전, 지원되는 암호 제품군, 그리고 "Client Random"라고 하는 무작위 바이트 문자열이 포함되어 있음.
'ServerHello' 메시지: ClientHello 메시지에 대한 응답으로 서버가 서버의 SSL 인증서, 서버에서 선택한 암호 제품군, 그리고 서버에서 생성한 또 다른 무작위 바이트 문자열인 "Server Random"를 포함하는 메시지를 전송
인증: 클라이언트가 서버의 SSL 인증서를 인증서 발행 기관을 통해 검증한다. 이를 통해 서버가 인증서에 명시된 서버인지, 그리고 클라이언트가 상호작용 중인 서버가 실제 해당 도메인의 소유자인지를 확인
premaster secret: 클라이언트가 "premaster secret"라고 하는 무작위 바이트 문자열을 하나 더 전송한다. premaster secret는 공개 키로 암호화되어 있으며, 서버가 개인 키로만 해독할 수 있다. (클라이언트는 서버의 SSL 인증서를 통해 공개 키를 받는다.)
개인 키 사용: 서버가 premaster secret를 해독한다.
세션 키 생성: 클라이언트와 서버가 모두 Client Random, Server Random, premaster secret를 이용해 세션 키를 생성합니다. 모두 같은 결과가 나와야 한다.
클라이언트 준비 완료: 클라이언트가 세션 키로 암호화된 "Success" 메시지를 전송한다.
서버 준비 완료: 서버가 세션 키로 암호화된 "Success" 메시지를 전송한다.
안전한 대칭 암호화 성공: 핸드셰이크가 완료되고, 세션 키를 이용해 통신이 계속 진행된다.
https://nuritech.tistory.com/25 ( 인증서 발급 과정 )
https://www.cloudflare.com/ko-kr/learning/ssl/what-happens-in-a-tls-handshake/