public/private subnet
- public
- vpc 내/외부 인터넷 통신이 가능하다
- 인터넷 통신하고자 하는 공인IP가 있어야함
- 리소스가 소속된 서브넷의 라우팅 테이블에 ‘0.0.0.0/0’ 목적지로 갖는 라우팅 인터넷 게이트웨이가 있어야함
- NetworkACL 과 보안그룹 규칙에서 허용해야함
- private
- 둘 다 다른 AZ에 설정해도 된다. 그치만 데이터 센터끼리 추가 통신이 발생해 트래픽 속도가 느려진다.
- 서브넷은 한 가용영역에 종속된다.
- 서브넷을 진짜 public 으로 바꾸는 방법
- 인터넷 게이트웨이를 라우팅 테이블에 설정하고 등록한다.
- 서브넷에서 인터넷 게이트웨이로 향하는 것이 라우팅 테이블에 등록되었다면 퍼블릭 서브넷이다.
VPC
- 1vpc = n서브넷
- 물리적으로 다른곳에 위치하지만 같은 사설망 IP 대역에 위치
- 서브넷도 CIDR 이 있다. 근데 AWS 에서 지정해둔 /16~/28 사이에서 사용해야한다.
- vpc 를 나눈것이 서브넷이기 때문에 대역폭은 서브넷보다 작아져야한다.
- 각 vpc 는 독립적이기에 서로 통신하지 않는다. vpc 피어링으로 트래픽을 라우팅 하는 것이다?
- vpc 의 가장 큰 대역은 /16, 가장 작은 대역은 /28.
- CIDR
- 클래스 없는 도메인간 라우팅 기법
- vpc 가 논리적 분리이고 서브넷은 실제 리소스 생성될 네트워크
- CIDR 값을 높게하면 더 범위가 정확함
- 범위가 좁아짐, /16 이면 앞에서부터 16비트 고정, /24 이면 앞에서부터 24비트 고정
- 가용영역(AZ:Available Zone)
- 서울은 a,c,b,d, 순으로 가용영역이 생성되었다. 그래서 a,c 사용 권장
- vpc 내 서브넷에 할당된 리소스라면 어느 서브넷이든 리소스와 통신 가능하다
- 가용영역을 나누는 이유
- 안정성
- 천재지변이 일어나도 다른 곳에 위치한 서버이기에 a서버 사용 불가능할 때 c 서버 사용
- 보안그룹과 NACL의 차이
보안그룹 | NACL |
---|
인스턴스 레벨 | 서브넷 레벨 |
허용 규칙 | 허용 및 거부 규칙 |
상태 저장 ( 규칙에 상관 없이 트래픽이 자동으로 허용 ) | 상태 비저장 ( 트래픽이 규칙에 의해 명시적으로 허용) |
트래픽 허용 여부 결정 전에 모든 규칙 평가 | 트래픽 허용 겨부 결정 중에 가장 낮은 규칙부터 순서대로 규칙 처리 |
인스턴스 시작시 지정하거나 나중에 보안그룹과 인스턴스를 연결하는 경우에만 적용 | 연결된 서브넷의 모든 인스턴스에 자동 적용 |
private/public subnet 분리
- private subnet에 EC2 배포하는 이유
- 보안 강화 : DDos 과 같은 퍼블릭 인터넷에서 발생하는 공격의 위험을 줄일 수 있음.
- 향상된 네트워크 성능 : 프라이빗 IP 주소 지정을 활용할 수 있어 네트워크 성능이 향상되고 대기시간이 단축됨
- 프라이빗 리소스에 대한 엑세스 : 프라이빗 서브넷을 사용해 vpc 내 리소스에 안전하게 연결 가능.
로드밸런서
- 현재 SSL/TLS 인증서가 로드밸런서에 등록되어 있음
- https 로드밸런서에 연결된 private 서버의 동작여부를 확인해야함
- 443 포트에 private subnet 의 서버 등록
- 외부에서 private subnet 에 접근 가능하다. 가능한 이유?
- nat instance 를 이용해 외부 인터넷과 연결해두었음
- 하지만 퍼블릭 ip 는 없기때문에 따로 외부에서 접속은 불가
- 그리고 이 로드밸런서도 우리의 클라이언트만 접근할 수 있도록 할 것임
- 따라서 private subnet 에 아무나 접근 할 수 없음
- ALB는 public 서브넷에 생성해 internet gateway 를 통해 들어오는 요청을 ALB 가 받아 private 서브넷으로 넘기도록
NAT instance
- private subnet 은 내부에서 외부로, 외부에서 내부로 접속할 수 없음. 하지만 private subnet 내 도커 설치, 업데이트 등을 위해 외부와 통신 가능하도록 할 수 있음
- 이를 위한 서버를 bastion host 라고 하며 nat instance 와 겸용할 수 있다.
- NAT Gateway 의 역할
- Private Subnet에 위치하는 인스턴스가 외부에 요청을 보낼 때 사용하도록 특화된 게이트웨이
- NAT Gateway 는 비용이 크기에 인스턴스를 새로 파 비용을 줄임
NAT
- 사설 네트워크에 속한 여러개의 호스트가 하나의 공인 IP 구조를 이용해 인터넷에 접속하기 위해 필요
- 인터넷 접속이 가능한 퍼블릭 서브넷에 nat gateway 를 생성해두고, private subnet 이 외부 인터넷으로 나갈 경우에만 사용하도록 라우팅 추가
- public/private 서브넷은 같은 VPC 안에 있으면 서로 통신할 수 있다는 점을 이용해 nat gateway 를 생성해주면 , 마치 대리기사 역할처럼 public 서브넷이 외부 인터넷 데이터를 private 서브넷에게 대신 전달
- NAT Gateway는 내부에서 외부로의 접속만 가능하며 외부에서 NAT Gateway를 이용하여 접속하는 것은 불가능하다는 특징을 가지고 있음. 따라서 NAT Gateway를 이용하면 외부 인터넷 연결에 의한 보안 문제도 일석이조로 해결할 수 있음.
퍼블릭 서브넷의 ec2에서 프라이빗 서브넷 접속하기
- bastion host 에서 = 같은 vpc 이니까 클라이언트와 같은 환경이라는 전제하에 테스트 진행했음. 허나 private subnet 과 연결된 nat instance 이기에 , 테스트를 위한 테스트 클라이언트 서버를 다시 팠음 (43.202.61.172)
- 해당서버는 앞으로의 클라이언트와 비슷한 환경임. 같은 vpc, public subnet, EIP 가짐
- S3+CDN 이 아니라 다르다고 볼 수 있지만, CDN + s3 end point 하면 같을 것으로 예상. 따라서 이 인스턴스(subnet) 열려있다는 전제하에 테스트 진행
- 하지만 curl https://test.aaa.ai 하면 로드밸런서의 80포트에 연결된 인스턴스의 보안그룹이 0.0.0.0 모두 오픈 되어있어야 가능.
- 근데 이렇게 하면 로컬에서도 private subnet 에 접근 가능 ..
그래서 hprobot-vpc 에서 보낸 요청만 로드밸런서에 연결된 private subnet 으로 향할 수 있게 해야함
- 최종 목적지인 private subnet 의 보안그룹, 그와 연결된 nat instance 의 보안 그룹 을 수정해야함
- private subnet
- public subnect 에서만 접근 할 수 있도록
- 이렇게 하고 있음
- public subnet
- 같은 vpc 에서만 접근 할 수 있도록
- nat instance 가????????
그래서 인스턴스 보안그룹 인바운드 규칙을 열어두고 로드밸런서 보안그룹을 막았다.
WIX 에 서브도메인 연결
- WIX에 CNAME 레코드 등록
- CNAME 레코드로 로드밸런서의 dns 이름을 등록해야함. A 호스트는 안됨.
- AWS 로드밸런서는 고정 IP 주소를 제공하지 않기 때문에, 보통 CNAME 레코드를 사용하여 DNS에서 로드밸런서를 가리키도록 설정
CDN 을 이용한 클라이언트와 연동하기
- 클라이언트는 S3 와 Cloud Front 를 이용해 배포하고 있다.
- 기존에는 public 서브넷 내에 ec2 로 띄워 클라이언트가 private 의 서버와 통신하는 것을 계획했으나 아니었다.
- cdn 으로 배포된 클라이언트는 같은 vpc 내 있을 수 없었고, 따라서 로드밸런서에 인바운드로 들어오는 값을 제한해야했다.
- 따라서 로드밸런서에 인바운드 규칙 설정이 아주 중요한 키가 되었다!
목표과제
서버 아키텍쳐는 비밀 ..
- Cloudfront로 배포한 리액트에서 VPC 내 Private subnet 안에 있는 spring boot server로 api요청을 보내고 있다.
- 이 때, public subnet 내 ALB는 Cloudfront의 요청만 받아들여 srping boot server로 요청을 보내도록한다.
보안그룹
NACL(VPC) | 모든 트래픽 허용 |
---|
ALB | CDN과 작업자 컴퓨터만 허용 |
public subnet | 모든 트래픽 허용 |
private subnet | public 서브넷 트래픽만 허용 |
Bastion host && NAT Instance | 모든 트래픽 허용 |
spring boot server instance | 퍼블릭 서브넷(10.0.1.0/24) 만 허용 |
시도1 : Limit access to your origins using the AWS-managed prefix list for Amazon CloudFront.
CDN의 원본에 ALB를 추가하고, ALB의 인바운드 규칙에는 CDN 접두사 목록을 추가함. Cloudfront의 IP는 변하기 때문에 IP범위가 바뀔 때 넣어주기 위해 접두사 목록을 추가함.
ALB 의 보안그룹 인바운드 규칙 설정을 통해 api 서버 (main-Spring) 에 도달하는 요청을 제한한다.
api 서버는 https 를 통해 배포되므로 아래와 같이 인바운드 규칙을 설정한다
유형 | 프로토콜 | 포트 | 소스 |
---|
HTTPS | TCP | 443 | pl-22a6434b - com.amazonaws.global.cloudfront.origin-facing [CDN 접두사 목록] |
결론1 ; 현재 cdn 접두사 목록으로 설정해두었을 때는 접속이 되지 않았다.
그래서 ALB의 보안그룹을 모두 열어두고 ALB 모니터링 로그를 활성화해(s3 버킷에서 로그확인할 수 있도록 함.) cdn 의 ip 주소를 확인했다.
해당 ip 주소를 인바운드 규칙에 그대로 입력하니 cdn 의 요청이 성공적으로 이루어졌다.
그리고 기존에 소스에 넣었던 cdn 접두사 목록을 확인했더니 요청이 찍힌 ip 가 접두사 목록에 없었다.
cdn 접두사 목록은 aws 가 관리하기에 개인이 임의로 추가할 수 없고, aws 가 업데이트 한다고 한다.
주기적으로 cdn 의 EIP 가 변경되기에 aws 에서 업데이트 한다고 한다.
근데 ALB 로그에 찍혔던 ip 는 요청 보낸 클라이언트가 연결한 ip 였다. ……
이 ip를 열심히 찾았다.
https://aws.amazon.com/ko/blogs/korea/aws-ip-ranges-json/
https://ip-ranges.amazonaws.com/ip-ranges.json
그래서 여기서 해당하는 ip를 찾았다
해당 ip 는 로드밸런서 ip 였다…
그래서 다시 원점으로 가면,
ALB 의 보안그룹 인바운드 규칙에 들어갈 CDN 의 엔드포인트(소스 등) 설정이 안먹는다
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/restrict-access-to-load-balancer.html
⇒ 인터넷을 통해 서비스되는 웹의 경우, cloudfront는 객체를 캐시하고 사용자에게 직접 제공하여 ALB에부하를 줄일 수 있다. 하지만 Cloudfront를 우회하고 ALB에 직접 액세스하게 된다면 문제가 된다. 따라서 CloudFront를 통해서만 ALB에 접근할 수 있도록 한다.
1. Cloudfront 내 설정
- 원본에 ALB를 추가해주었고, 이 ALB 원본에 사용자 지정 헤더를 추가해주었다.
- 이를 통해 cloudfront가 ALB에 요청을 보낼 때 HTTP 헤더를 추가하도록 설정한다.
2. ALB 리스너 규칙 설정
- 새규칙을 추가한다. 이 규칙에 HTTP 헤더를 선택해서 CloudFront에 추가해주었던 헤더와 같은 key-value값으로 지정한다.
- 동작 추가를 선택하여 대상그룹을
hprobot-main-spring
으로 지정해주어 헤더를 담은 요청에 대해 spring서버로 갈 수 있게 설정한다.
- 기본설정을 수정한다. 응답 코드에 403을 입력하여 헤더를 담지 않을 경우 기본으로 액세스 거부를 한다.
그럼 헤더의 유무에 따라 라우팅 되는 곳이 다르다 wow 다음 그림은 Postman으로 응답을 확인해봄.
그치만 Cdn 브라우저에서 관리자모드 헤더 값을 확인할 수 있어 같은 값을 보낸다면 필터링이 소용 없어지않을까 싶다. 그리고 이렇게 설정 했더니 클라이언트에서 403에러와 CORS 에러가 났다.
결론 2 ; 다시 원점으로 돌아오면, ALB의 보안그룹 인바운드 설정에 CDN IP를 넣어주어야 하는데 그 값을 모르겠다.
- CDN IP 범위인 prefix list를 넣어줘도 안되고,
- 시도1을 포기하고 시도2로 헤더값으로만 설정해도 안되는 상황..
- 그렇다면 springboot로 api요청을 할 때, CDN ip로 요청이 가는게 맞을까?? 가능은 한 것일까..?