aws:SourceIp 조건만 믿으면 안 되는 이유 — VPC 엔드포인트 환경에서의 IP 기반 접근 제어 함정

이군·2026년 4월 14일

들어가며

IAM 정책에서 aws:SourceIp 조건을 사용해 API 호출을 특정 IP 대역으로 제한하는 것은 가장 흔한 네트워크 기반 접근 제어 패턴 중 하나입니다. 사무실 IP나 VPN 대역에서만 AWS 콘솔 접근을 허용하거나, 특정 CIDR에서만 S3 버킷 조작을 가능하게 하는 정책은 거의 모든 조직에서 사용하고 있을 겁니다.

그런데 이 정책이 VPC 엔드포인트(AWS PrivateLink)를 통한 호출에서는 의도대로 동작하지 않을 수 있다는 사실을 알고 계셨나요?

문제의 본질

aws:SourceIp의 동작 원리

aws:SourceIp는 API 요청의 원본 소스 IP 주소를 담고 있는 글로벌 조건 키입니다. 인터넷을 통해(퍼블릭 엔드포인트로) AWS API를 호출하면, 이 값에는 호출자의 퍼블릭 IP가 정상적으로 들어갑니다.

VPC 엔드포인트 경유 시 달라지는 점

문제는 VPC 엔드포인트(인터페이스 엔드포인트, Gateway 엔드포인트 모두)를 통해 AWS 서비스에 접근할 때 발생합니다.

VPC 엔드포인트를 경유하는 요청에서는 aws:SourceIp 조건 키가 채워지지 않거나, 예상과 다른 값이 들어갑니다. 이는 요청이 퍼블릭 인터넷을 거치지 않고 AWS 내부 네트워크를 통해 라우팅되기 때문입니다.

실제 위험 시나리오

다음과 같은 S3 버킷 정책을 생각해 봅시다:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "RestrictBySourceIp",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-secure-bucket",
        "arn:aws:s3:::my-secure-bucket/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "203.0.113.0/24"
        }
      }
    }
  ]
}

이 정책의 의도는 203.0.113.0/24 대역 외부에서의 모든 S3 접근을 차단하는 것입니다.

하지만 VPC 엔드포인트를 통해 접근하는 EC2 인스턴스나 Lambda 함수에서는 aws:SourceIp가 평가되지 않기 때문에, 이 Deny 조건이 매칭되지 않아 접근이 허용될 수 있습니다.

반대 케이스도 문제입니다. Allow 정책에서 aws:SourceIp를 조건으로 사용하면, VPC 엔드포인트 경유 시 조건이 매칭되지 않아 정당한 접근까지 차단되는 상황도 발생합니다.

요약하면:

정책 유형의도VPC 엔드포인트 경유 시 실제 동작
Deny + NotIpAddress + aws:SourceIp허용 IP 외 차단조건 미매칭 → Deny 미적용 → 의도치 않은 허용
Allow + IpAddress + aws:SourceIp허용 IP만 접근조건 미매칭 → Allow 미적용 → 정당한 접근 차단

aws:VpcSourceIp — 빠진 퍼즐 조각

AWS는 이 문제를 해결하기 위해 aws:VpcSourceIp 조건 키를 제공합니다.

  • aws:SourceIp: 퍼블릭 엔드포인트를 통한 요청의 소스 IP
  • aws:VpcSourceIp: VPC 엔드포인트를 통한 요청의 원본 프라이빗 IP

aws:VpcSourceIp는 요청이 VPC 엔드포인트를 경유할 때만 채워지고, 퍼블릭 엔드포인트를 통한 요청에서는 채워지지 않습니다. 정확히 aws:SourceIp상호 보완적인 관계입니다.

모범 사례: 두 조건 키를 함께 사용하기

VPC 엔드포인트 환경과 퍼블릭 접근을 모두 커버하려면, 두 조건을 조합해야 합니다.

패턴 1: Deny 정책에서의 조합

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyAccessFromUnauthorizedNetworks",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-secure-bucket",
        "arn:aws:s3:::my-secure-bucket/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "203.0.113.0/24"
        },
        "NotIpAddress": {
          "aws:VpcSourceIp": "10.0.0.0/16"
        },
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0123456789abcdef0"
        }
      }
    }
  ]
}

주의: 위 정책에서 동일한 연산자(NotIpAddress)를 두 번 사용하면 JSON 키 중복으로 마지막 값만 적용됩니다. 실제 구현에서는 아래와 같이 하나의 연산자 블록 안에 두 키를 넣어야 합니다.

패턴 2: 올바른 조합 (권장)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnlessFromCorporateOrVpc",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::my-secure-bucket",
        "arn:aws:s3:::my-secure-bucket/*"
      ],
      "Condition": {
        "NotIpAddress": {
          "aws:SourceIp": "203.0.113.0/24",
          "aws:VpcSourceIp": "10.0.0.0/16"
        },
        "StringNotEquals": {
          "aws:SourceVpce": "vpce-0123456789abcdef0"
        }
      }
    }
  ]
}

이 정책은 다음 세 가지 경우를 모두 벗어나는 요청만 Deny합니다:

  • 퍼블릭 소스 IP가 203.0.113.0/24가 아니고
  • VPC 내부 소스 IP가 10.0.0.0/16이 아니고
  • 지정된 VPC 엔드포인트를 통한 요청도 아닌 경우

핵심: Condition 블록 내에서 같은 레벨의 조건들은 AND로 평가되지만, 같은 연산자 내의 서로 다른 키는 각각 독립적으로 평가되어 하나라도 매칭되면 해당 연산자 조건을 충족합니다. aws:SourceIpaws:VpcSourceIp는 동시에 채워지지 않으므로 이 구조가 정확히 의도대로 동작합니다.

패턴 3: VPC 엔드포인트 + VPC 조건으로 보강

네트워크 경계를 더 엄격하게 통제하려면 aws:SourceVpcaws:SourceVpce를 추가로 활용합니다:

{
  "Condition": {
    "StringNotEquals": {
      "aws:SourceVpc": "vpc-0abcdef1234567890"
    },
    "NotIpAddress": {
      "aws:SourceIp": "203.0.113.0/24"
    }
  }
}

점검 체크리스트

기존 IAM 정책과 리소스 정책에서 이 이슈에 해당하는지 빠르게 점검하려면:

  1. aws:SourceIp를 사용하는 모든 정책을 검색한다. IAM 정책, S3 버킷 정책, KMS 키 정책, SQS 큐 정책 등 리소스 정책 전체를 대상으로 합니다.
  2. 해당 리소스에 VPC 엔드포인트 경유 접근이 존재하는지 확인한다. S3 Gateway 엔드포인트, 인터페이스 엔드포인트 등이 설정되어 있다면 반드시 검토 대상입니다.
  3. aws:VpcSourceIp 또는 aws:SourceVpce/aws:SourceVpc 조건이 함께 사용되고 있는지 확인한다. 하나라도 누락되어 있다면 잠재적 위험이 존재합니다.
  4. CloudTrail에서 VPC 엔드포인트 경유 API 호출의 sourceIPAddress 필드를 확인한다. VPC 엔드포인트 경유 시 이 필드에 VPC 엔드포인트 ID가 기록되는지 확인하여 실제 트래픽 패턴을 파악합니다.

마치며

aws:SourceIp는 직관적이고 편리한 조건 키이지만, VPC 엔드포인트가 보편화된 현재 환경에서는 이것만으로 네트워크 기반 접근 제어가 완성되지 않습니다. 특히 하이브리드 환경(퍼블릭 + VPC 내부 접근이 혼재)에서는 aws:VpcSourceIp와의 조합이 필수입니다.

보안 아키텍처의 핵심은 하나의 제어가 실패했을 때 다른 제어가 보완하는 다층 방어(Defense in Depth)입니다. IP 기반 접근 제어에서도 동일한 원칙이 적용됩니다.

기존 정책을 지금 바로 검토해 보시기 바랍니다.


참고 자료

profile
이군의 보안, 그리고 생각을 다룹니다.

0개의 댓글