소마 프로젝트를 진행하면서, 인프라 쪽을 내가 어느 정도 담당하고 있어서(사실 담당한다고 하기에도 민망할 정도로 기본적인 부분들만 담당하긴 하지만) RDS를 띄워보기로 했다. Private Subnet에 RDS를 띄우기로 했는데, 문제는 "로컬에서 Private Subnet에 어떻게 접근하는가?" 였다.
Private Subnet은 외부와 단절된 네트워크로, 외부에서 직접 접근이 불가능하다. NAT Gateway를 둬서 Private Subnet에서 외부로 트래픽을 보낼 순 있어도, 외부에서 먼저 Private Subnet으로 트래픽을 보낼 순 없다. VPN등을 통해 직접 로컬에서 Private Subnet으로 연결할 순 있으나, 비용이 무시무시하다는 소문이 들려서 다른 방법을 찾아보기로 했다
당장 떠오르는 방법은 Public Subnet에 EC2를 둔 후, ssh로 EC2에 원격으로 연결한 다음 거기서 Private Subnet으로 접근하는 것. 같은 VPC안의 애들끼리는 서로 통신이 가능하기 때문에 이 방법을 쓸 수 있을 것이다. 이렇게 외부에서 내부 네트워크로의 안전한 접근을 제어하기 위해 사용되는 중간 서버를 Bastion Host라고 부른다.
이렇게 하면 로컬에서 Private Subnet에 있는 RDS로 create등의 쿼리를 작성해 날릴 수 있다. 그러나 "얘를 로컬에서 돌리고 있는 스프링부트와 어떻게 연결하는가"가 숙제. 스프링부트에서 만들어지는 쿼리를 터미널에 인풋으로 주도록 내가 직접 구축을 해야 하나..? 그건 너무 에바같은데..
이 때 ssh 포트 포워딩(다른 말로는 ssh 터널링)을 통해 이 문제를 해결할 수 있다. ssh 포트포워딩이란 ssh를 사용해 로컬 머신과 원격 서버 사이에서 포트 전달을 설정하는 것으로, 이를 통해 로컬에서 특정 포트로 트래픽을 보내면 ssh터널(ssh를 통해 연결된 통로라고 생각)을 통해 원격서버의 특정 포트로 보낼 수가 있다. 즉 내가 로컬의 3306포트와 원격 서버의 3306포트를 포트포워딩하면, 내가 로컬의 3306포트로 보내는 트래픽을 원격 서버의 3306포트로 보낼 수가 있는 거다. (참고로 이 예시는 로컬 포트 포워딩에 해당하며, 리모트 포트 포워딩을 하면 원격 서버에서 특정 포트로 들어오는 트래픽을 내 로컬 머신의 포트에서 받을 수 있다)
이런 로컬 포트 포워딩은 다음과 같이 설정해 사용 가능하다
ssh -L [로컬에서 사용할 포트]:[최종적으로 접근할 곳(ip:port형태)] [SSH Server 주소]
예시로, aws에서 지급받은 pem키와 함께 사용하려면 다음과 같이 하면 된다.
ssh -i [pem키 경로] -L 3306:[RDS 엔드포인트]:3306 [사용자명(ex:ubuntu)]@[Bastion Host public ip]
이렇게하면 로컬의 3306포트와 Private RDS의 3306이 연결됐으니 이제 스프링부트에서도 datasource를 내 로컬의 3306으로 한 뒤 쓰면 된다. 물론 각각 보안그룹들이 다 설정돼있어야 한다!(RDS는 Bastion으로부터 3306포트로 오는 인바운드 허용, Bastion은 22번 인바운드와 3306아웃바운드 허용 등..) 이 때 Public Subnet에 둔 EC2는 점프호스트로 쓰는 거라고 볼 수 있다
하지만! SSM이란 서비스를 사용하면 좀 더 쉽게 Private Subnet접근이 가능하다.
SSM이란?
AWS System Manager. Simple System Manager라고도 불리며 이의 줄임말이 SSM이다. 다양한 기능들을 제공하는데, Session manager라는 걸 통해 EC2접속을 할 수 있는 서비스도 제공한다.
https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html
Session Manager를 사용하면 기존에 했던 것처럼 Bastion Host를 둘 필요 없이 Private Subnet에 있는 EC2인스턴스에 직접 접근이 가능하다(당연히 퍼블릭도 가능). ssh로 연결할 때 사용하던 pem키 관리 및 EC2인스턴스들에 22번 포트를 여는 인바운드 설정도 할 필요가 없다. 즉 더 안전하게 사용 가능한 방법이라고도 볼 수 있다. 또한 포트포워딩도 지원하기 때문에 로컬에서 Private Subnet에 있는 RDS로의 접근 역시 가능하다!
(Session Manager를 통해 EC2들에 대한 직접 액세스는 가능하나 RDS등은 직접 액세스는 안 돼서 포트포워딩을 거쳐야 함. 즉 EC2라는 관리 인스턴스를 "점프 호스트"로 사용해 RDS로 접근하는 것이며, ssh 포트포워딩을 통해 public에 있던 EC2를 점프호스트로 쓰던 것과 같은 원리이다.)
참고로 이때 SSM을 통해 직접 액세스하게 되는 EC2는 22번 인바운드는 열릴 필요가 없으나, 443번 아웃바운드는 열려있어야 한다. 해당 EC2에서 AWS SSM에게 지속적인 폴링을 통해 연결을 유지하기 때문이다. 따라서 보안그룹 설정시 꼭 주의할 것. 관련된 내용은 아래 링크의 [엔드포인트에 연결] 섹션을 참고하면 된다
그럼 본격적으로 SSM으로 포트포워딩을 설정해 로컬에서 Private Subnet의 RDS에 접속하는 법을 알아보자.
1. 로컬환경에 aws cli 설치하기
2. aws IAM을 만든 다음, Access Key와 Secret Access Key를 발급받는다.
3. 로컬에서 터미널을 띄우고 aws configure를 입력해 구성한다
$ aws configure
AWS Access Key ID [None]: {각자에게 주어진 Access Key}
AWS Secret Access Key [None]: {각자에게 주어진 Secret Access Key}
Default region name [None]: ap-northeast-2
Default output format [None]: json
4. 로컬에 Session Manager Plugin을 설치한다
5. EC2를 띄우고, 그 EC2에 AmazonSSMManagedInstanceCore라는 정책이 있는 역할을 부여한다
참고로 EC2에 SSM agent가 설치돼있어야 한다. aws에서 제공하는 AMI로 만들어진 EC2들은 ssm agent가 기본적으로 깔려있는 애들이 많다! 다음 링크의 [SSM Agent의 상태 확인] 섹션을 참고해 SSM agent가 설치돼있는지 살펴보고, 안돼있으면 설치해야한다. 설치된 상황이라면 해당 역할을 부여한 후 SSM agent를 재시작해준다.
재시작하는 커맨드는 상태 확인 커맨드에서 status만 restart로 바꾸면 된다.
https://docs.aws.amazon.com/ko_kr/systems-manager/latest/userguide/ami-preinstalled-agent.html
6. 터미널에 다음 커맨드를 입력한다
aws ssm start-session --target {EC2 인스턴스의 id} \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"portNumber":["3306"],"localPortNumber":["3306"],"host":["{RDS 엔드포인트}"]}'
그러면 ssh 포트포워딩을 했을 때처럼 로컬의 3306포트와 RDS의 3306포트가 연결된다.
참고한 글
https://blog.naver.com/PostView.naver?blogId=alice_k106&logNo=221364560794
https://musma.github.io/2019/11/29/about-aws-ssm.html
https://hwan-shell.tistory.com/382
'INFRA & DEVOPS > AWS' 카테고리의 다른 글
[AWS] Elastic IP EC2에 부여하고 도메인과 연결하기 (0) | 2023.09.05 |
---|---|
[AWS] IAM이란? (사용자, 정책, 그룹, 역할, 정책 평가 방법 등등) (0) | 2023.07.21 |