AWS 리소스 접근 제한 설정하기

dev_qorh·2022년 10월 11일
0

CatchCatch

목록 보기
14/18

들어가기 앞서..

이 구성도 lambda가 포함되지 않은 구성이다. 정리는 필요하지만 중간 회고를 위해 작성한다.

VPC가 괴롭혀요

오늘이 11일이고, vpc 접근 제한 설정을 시작한 것은 9일이다.. 정말 많은 시간을 할애해서 aws vpc관련된 많은 정보들을 알 수 있었고, 경험했고, 아직 부족함을 뼈저리게 느끼게 되었다.

기능이 어느 정도 구성되고 난 후에 다시 쓰는 글이지만 아직까지도 몇몇은 그 완성을 확신하지 못하고 있다. (lambda의 vpc 연결과 그 서브넷 내 리소스와의 통신, NAT instance는 정말 제 역할을 하고 있는 지 등)

하지만, 원래는 알 수 없었던 많은 지식들을 접할 수 있었다. 예를 들면,

  1. lambda에 vpc를 연결하게 되면, 설정한 서브넷과 보안그룹에 맞는 네트워크 인터페이스가 기본으로 생성된다. 만약 lambda들을 엮을 수 있는 eni가 있다면, 그것을 사용한다.

  2. VPC에서 생성되는 서브넷은 여러 개를 둘 수 있고, 보안 그룹 및 라우터 테이블 설정에 따라 private 하게도, public 하게도 사용가능하다.

  3. 라우터 테이블은 CIDR (Classless Inter-Domain Routing) 에 기반하여 동작한다. 대상으로는 서브넷의 CIDR, 인터넷 게이트웨이, 네트워크 인터페이스를 대상으로 지정할 수 있다.

  4. 보안 그룹의 인바운드 아웃바운드 정책은 네트워크 인터페이스, 인터넷 게이트웨이 기준으로 설정할 수 없다. 오직 CIDR을 기반으로 하거나, 보안그룹, 혹은 접두사 목록 (s3, dynamodb와 같은 특수한 리소스 접근 엔드포인트)

    • 그래서, 보안그룹에서 보안그룹으로 바운딩 설정을 하는 것의 의미를 모르겠다.
    • 공식 문서에 따르면, 프라이빗 ip 주소 10.0.10.23을 갖는 리소스가 (네트워크 인터페이스 등으로) 보안 그룹 sg-031을 갖는다면, 보안 그룹 sg-d92(아웃바운드로 sg-031가 연결된)를 갖는 퍼블릭 리소스가 프라이빗 리소스에 접근을 하는 것이 허용된다는 의미인 것 같다. 보안 그룹간의 중복은 생기지 않고, 트래픽이 허용될 때 라우터에 의해 목적지가 결정되는 것으로 보인다.
  5. lambda에 접근하는 방법으로 function url/api gateway 호출이 있다. (외부 공개 시) vpc에 연결하지 않으면 aws에서 자체적으로 제공하는 네트워크 인터페이스를 통해 어디서든 접근 가능하지만 vpc를 지정해주면 (1)에서 설명한 것과 같은 동작을 취한다.

  6. 인터넷 게이트웨이를 거치는 트래픽은 공인 ip로 되어있어야 한다. NAT Instance 자체에서는 source/destination 체크를 비활성화 하여 내부망 ip를 공인 ip로 변환하는 기능을 가져 네트워크 영역을 구분하여 사용할 수 있는 것이다.

  7. NAT Instance는 잘 구축되어야 한다. 확실하게 NAT Instance를 지원하는 AMI를 사용하지 않으면 아무리 설정을 해줘도 트래픽이 전달되지 않는다. (너무 감사드리는, 이를 통해 NAT Instance가 잘못 되었다는 걸 알 수 있었던, 혹은 나의 무지인.. 글!)

  8. AWS에서는 VPC의 Reachable Analyzer를 통해 리소스간의 통신을 테스트해 볼 수 있다. 안타깝게도,, aws 네트워크 리소스를 기반으로 하는 테스트라서 eni,igw,endpoint와 같은 친구들끼리의 연결성만 테스트 가능하다. (사실 단정하긴 어렵다. 깊게는 사용하지 않은 것 같다.)

    • lambda eni에서 igw를 연결하려고 수십번 시도하다가... 그저 NAT Instance가 역할을 잘해줄 것으로 기도하기로 하였다 (배포까지 시간이 없다..)
    • 그래도 인스턴스를 직접 다룬 패킷이 없는 상황에서 오간 것이 있는 걸 보아하니, lambda의 패킷이 잘 통과하는 것 같다. 통신 간의 패킷을 분석할 수가 없었다.

Lambda 정책

글의 다른 부분들은 VPC를 나누고 접근을 제한하는 것이지만 lambda iam은 직접 코드에서 설정한다. 간단하게 설명하면, cloudformation에서 각 AWS::Serverless::Function 의 VPCconfig의 subnet과 security group을 위치시키고 싶은 영역의 id로 두면 된다.

또, IAM 역할이 있어야 한다. AWSLambdaVPCAccessExecutionRole 과 나는 SecretManager의 읽기 권한을 묶어 IAM Role을 세팅하고 모든 함수의 Role에 arn을 붙여줬다.

리소스별 제한 설정

S3 접근 제한

이후 기술

Lambda 접근 제한 (with NAT Instance)

NAT Instance 도입 이유?

백엔드로 활용하게 되는 lambda는, 카카오톡 api를 사용하기 위해서 outbound 요청을 보내야 한다. 하지만 동시에 lambda endpoint 접근 자체는 private subnet에 위치 시켜 외부의 접속을 차단해야한다. 이를 위해선, 외부 네트워크와 연결되기 위한 NAT(네트워크 주소 변환) 서비스가 구성되어야 한다.

구현을 위해서 NAT Gateway를 막연하게 떠올렸고 이를 도입하고자 요금을 알아보았다. 놀랍게도, multiple AZ 환경을 고려한 2개의 월 단위 비용이 10만원을 넘는다는 것을 알게 되었다. 당연하게 공식 문서에서는 편리함을 앞세워 NAT Gateway를 사용할 것을 권고하지만, 동시에 NAT Instance라는 방법이 있다는 것도 알 수 있었다.

그리고 다른 분이 분석한 instance vs gateway 요금 비교 관련 글도 찾아볼 수 있었다. 글에 따르면, t3.nano 1년 선결제 예약 인스턴스, GP 8GB EBS를 사용해 인스턴스 대당 월 $3.5 정도로 구성할 수 있으며 그 성능 또한 준수한 것을 알 수 있었다.

NAT Instance 구축하기

해당 챕터는 구성 후 많은 삽질에 의해 고쳐졌습니다. 참고만 하시고 공식 메뉴얼대로 하시는 걸 추천드려요.

aws 공식 메뉴얼에 따라 하나하나 해보기로 한다.

  1. VPC 서브넷을 구축하고 IGW를 VPC에 부착한다.
    • 여기서 나는 multiple AZ를 고려하여 이전에 사용하던 서브넷 4개를 그대로 활용하기로 한다.
  2. NATSG 보안 그룹을 생성한다. 이는 NAT Instance에서 명시되는 보안 그룹이다.
    • private subnet 인스턴스로부터의 인터넷 바인딩 트래픽 뿐만 아니라 SSH도 수신할 수 있도록 해야 한다.
    • 아래 그림을 보면, 인바운드 규칙의 HTTP, HTTPS 허용에 각 가용영역의 ipv4 CIDR이 포함된 것을 볼 수 있다.
  3. EC2를 사용하여 NAT Instance를 구축한다.
    • 위 글에서도 나왔듯이, t3.nano를 사용하고자 하였다. 하지만 네트워크 사양이라고 하는 5Gbit/s가 어느정도 단위인지 검색을 해보다 ec2 network 성능을 분석한 농심의 글을 볼 수 있었다.
    • 글에 따르면, 500MB 파일을 2만명이 14시간 안에 다운 받는 데에 필요한 네트워크 성능이 1.5Gbit/s 라고 하니, 파일 입출력이 lambda에 없는 우리 서비스는 크게 고려하지 않아도 될 듯 하였다.
    • 네트워크 성능에 관한 자료들을 좀 찾아봤다. AWS가 제시하는 네트워크 성능은 인터페이스의 스펙이다. / 18년 글이지만, 인스턴스 별 실제 네트워크 성능 비교
    • 결론적으로 사전에 큰 고려를 하지 않기로 한다. 어차피 Scale-Up을 할 수도 있고 그 정도 상황이 가정된다면 NAT Gateway 도입도 할 수 있을 듯 하니까.
  4. NAT Instance를 위해 SrcDestCheck 속성을 비활성화 해주기
    • EC2 Instance는 기본으로 source/destination 체크를 수행한다고 한다. 이는 인스턴스가 주거나 받는 모든 트래픽에 인스턴스가 source 혹은 destination이어야 한다는 의미다. 하지만 NAT Instance는 source/destination이 자기 자신이 아니어도 트래픽을 주거나 받을 수 있어야 하기에 해당 옵션을 꺼주어야 한다.
    • 위 작업은 AWS CLI로도 수행할 수 있다고 하니, 필요하다면 나중에 참고하도록 한다.
  5. 탄력적 IP를 할당하고 NAT Interface를 알맞게 연결해준다.
    • NAT Interface는 기존에 RDS를 쓸 때 만든게 하나 더 있었다. 잘 확인하고 알맞게 등록한 후, NAT Instance의 private ip도 같이 등록해준다.
  6. Main route table이 NAT Instance로 트래픽을 보낼 수 있도록 업데이트 해준다.
    • VPC의 Main Route Table(기본: "예"로 설정되어 있는 rtb)에서 아래와 같이 0.0.0.0/0의 목적지를 NAT Instance로 가도록 라우팅을 추가해준다.
    • main rtb의 서브넷 연결에서, private subnet을 연결해준다.

lambda 연결

연결의 의미?? 가설과 테스트

사실 NAT Instance를 연결해도 이것이 무엇을 의미하는지 정확하게 이해하지는 못했다. 그래서 여러가지 가설을 세워보았다.

  • lambda는 vpc가 지정되지 않았을 때 api gateway와 함께 사용된다면, 함수는 공통 영역에서 배포되어 모두가 접근할 수 있고 아웃바운드도 열려있어 인터넷으로의 접근이 가능하다. -> 기본적으로 lambda는 사용자의 VPC에 연결되지 않는다고 한다. 즉, lambda를 외부 접속으로부터 숨기기 위해서는
  • lambda를 subnet에 둘 경우, 배포된 API Gateway endpoint는 public에 있는 NAT Instance로의 접근이 되고 내부적으로 eni를 통해 private lambda로 연결이 전송될 것이다. / 혹은 endpoint 자체가 새롭게 구성되거나 구성되지 않아 오류를 발생시킬 수 있다.
  • private subnet에 rds를 위치시키면 동일한 subnet이기에 lambda는 rds에 접근할 수 있다.
  • 위의 모든 옵션은 거의 보안 그룹의 인바운드 설정을 통해 제어할 수 있다.

RDS 접근 제한

설정 방법?

단계를 나누어 설명하고 싶지만, 정리하기엔 시간이 모자라다. 조치했던 것들을 나열하며 복기해보겠다.

  1. 기존 RDS는 private subnet에 위치하고 있었다. 하지만 테스트를 위해서 당시엔 private subnet의 보안그룹 (rds eni의 보안그룹)이 모든 ip에 열려있었고 라우팅 테이블도 igw를 향하게 되어 있었다.

  2. 우선, 서브넷을 분리하여 public과 private으로 나누고, 각각에 맞도록 라우팅 테이블을 구성한다.

    • public 서브넷은 NAT Instance를 위치시킨 다음, igw를 0.0.0.0/16 으로 설정하여 10.0.0.0/16의 내부 트래픽이 아닐 경우 외부 인터넷으로 연결시킨다. 또, 10.0.0.0/16 의 트래픽은 local로 연결하여 리소스 간 통신이 가능하게 해준다.
    • private 서브넷은 0.0.0.0/16 의 외부 트래픽을 NAT Instance의 네트워크 인터페이스 혹은 instance id로 연결한다. NAT Instance는 해당 트래픽을 받아 연결된 탄력적 ip로 바꿔 igw로 보내준다. 마찬가지로, 10.0.0.0/16은 local로 설정하여 내부 통신을 설정한다.
  3. 보안그룹을 설정한다.

    • public 서브넷의 보안 그룹인 NATSG (NAT instance eni 포함)은 inbound로 private subnet CIDR의 http/https 요청을 허용한다. 그리고 NAT instance에 접속하기 위한 SSH 포트를 본인의 ip로 허용한다. (물론, public ip여야 함)
    • 사실 공식문서에서 아래와 같이 잘 설명되어 있지만, 기존에 호작질(?)을 해놓은 사람이라면.. 커스텀할 수 밖에 없어진다.. 나처럼..
    • private 서브넷은 나같은 경우 다 열어 두었다. 이것을 lambda와 연계하여 설정하기엔 너무 꼬여버리기에 (api gateway의 호출인데 private subnet일 때, 같은 private subnet의 rds에 연결되려면 보안그룹이 세팅 되있어야 하는데, 요청이 나가는 것은 public subnet의 NAT Instance여야 하고... 또...) 그냥 열었다. 어차피, 서브넷으로 나누어 두었기 때문에 외부에서 private subnet으로 바로 요청은 불가능하다고 판단하기 때문이다. (일단 rds 접근이 안된다.)
  4. 이후, NAT Instace SSH를 통해 mysql에 접속하면 된다. rds의 엔드포인트를 활용하여 내부 접속을 시도하면 된다.

    • 아래 그림이면 잘 설명 된다. ssh는 ec2에 연결된 탄력적 ip로 연결해주고 mysql host는 rds의 엔드포인트로 해주면 된다.

이후 설정해야 하는 것

  • 가용 영역을 확보하기 위해 읽기 전용 DB를 다른 AZ에 배포한 다음 (private) 마찬가지로 보안 그룹 설정 및 라우팅 테이블 설정.

궁금한 것

  1. 알게된 것 중 공개된 Lambda end point에 접근한 것들은 생성된 네트워크 인터페이스를 통해 사용이 된다고 하였는데, 그 정확한 내부 동작을 알 수가 없었다.

    • reachable analyzer를 통해서 시도해보아도, NAT Instance가 연결된 lambda 환경이었기에 판단이 어려웠다.
    • lamdba를 public subnet에 위치시키면, 내부적으로 NAT Instance로 향하는 라우팅이 되어 있지 않기 때문에 public ip를 가질 수 없었고 igw로의 연결은 당연히 실패한다. (igw 특성에 의해)
    • private subnet에 위치시키면, NAT Instance로 가야한다고 생각했지만, Destination을 igw로 해서 그런지 직접 igw로 가는 트래픽이 발생되더라. 당연히 라우팅 테이블에 의해 막히게 된다.
  2. 8에서 패킷을 분석할 수 없었던 것은 왜일까. api gateway가 열어두는 url이 어떻게 동작하는 지 알아보면 좋을 듯 하다.

profile
기술로써 가치를 만들고 싶은 사람입니다.

0개의 댓글