정책 리스크를 파악하십시오. 정책에 대한 질문을 일상 언어로 하십시오. 데모 신청하기 →

Published:

가급적 서비스 중단 없이 침해된 EC2 자격 증명 격리하기

by FireMon

침해된 인스턴스 자격 증명을 격리하는 기법은 여러 가지가 있습니다. 쉬운 방법일수록 장애를 일으킬 가능성이 크지만, 애플리케이션을 중단시키지 않고 공격자를 차단할 수 있는 창의적인 방법도 있습니다.

지난 몇 년간 Amazon은 공격자가 AWS 인스턴스에 할당된 자격 증명을 탈취하고 악용할 위험을 줄이기 위해 상당한 진전을 이루었습니다. 물론 이 중 상당수는 모두가 여전히 이야기하는 그 대규모 침해 사고 이후에 이루어진 것이지만, 이제는 이런 유형의 공격을 막을 수 있는 훨씬 나은 도구가 마련되어 있습니다. 그럼에도 이러한 공격은 여전히 매우 흔하며 모든 조직의 클라우드 위협 목록에서 상위를 차지하고 있습니다.

지난달 AWS는 인스턴스 자격 증명을 제한하는 새로운 정책 옵션을 공개했습니다. 이것이 이 글을 쓰게 된 계기입니다. 여기에 더해 잠시 후 말씀드릴 클라우드 보안 커뮤니티의 흥미로운 발견도 한몫했습니다. 이 새로운 기능이 아무리 훌륭하고, AWS가 자격 증명 유출에 대한 GuardDuty 탐지 기능을 획기적으로 개선했다 하더라도, 어느 시점에는 저희 제품과 같은 도구로부터 알림을 받고 사고 대응 프로세스를 가동해야 할 수 있습니다.

AWS가 인스턴스 자격 증명을 제한하는 새로운 정책 옵션을 공개했음을 보여주는 이미지.

수년에 걸쳐 저는 다양한 격리 방안을 정리하고 테스트해 왔으며, 그 대부분은 제가 Will Bengtson과 함께 구성한 클라우드 사고 대응 교육 과정의 실습으로 마련되어 있습니다. 장애를 일으키지 않으면서 공격자를 격리하려면 놀라울 만큼 세밀한 고려가 필요합니다. 인스턴스 자격 증명을 다룰 때는 사실상 세 가지 구성 요소와 상호작용하게 됩니다. 권한을 처리하는 IAM 서비스, 해당 자격 증명을 인스턴스에 전달하는 인스턴스 메타데이터 서비스(IMDS), 그리고 인스턴스 내부에서 그 자격 증명을 사용해 애플리케이션을 실행하는 코드/SDK입니다. 여기서는 의도적으로 일부 내용을 단순화했으며 Service Control Policy와 리소스(버킷) 정책은 다루지 않는다는 점을 밝혀 둡니다. (이 글의 모든 스크린샷은 제가 만든 교육 자료에서 거리낌 없이 가져온 것이니 당국에 신고하지 말아 주십시오.)

모르는 분들을 위해 간단히 배경을 설명하자면, 인스턴스에 IAM 역할을 할당하면 해당 인스턴스에는 그 역할의 권한을 부여하는, 자동으로 교체되는 자격 증명이 제공됩니다. 그러나 공격자가 SSRF 공격이나 SSH 무차별 대입 등으로 인스턴스에 접근할 수 있게 되면, 그 자격 증명을 복사해 AWS 외부에서 또는 자신이 통제하는 AWS 계정에서 사용할 수 있습니다.

사전 준비로 Will은 S3 버킷에 내부 연결을 시도하고 자격 증명이 유효한지 결과를 알려주는 작은 애플리케이션을 작성했습니다(참고로 화면에 표시된 IP 주소는 더 이상 유효하지 않습니다).

인스턴스에 할당된 IAM 역할이 자동으로 교체되는 자격 증명을 제공하는 모습을 보여주는 이미지.

옵션 1: 역할에 Deny All 정책 추가

이 방법이 단연 가장 쉽고 빠릅니다. IAM 역할에 Deny All 정책을 추가하면 모든 API 호출이 실패하므로 공격자는 더 이상 피해를 입힐 수 없습니다.

옵션 1: 역할에 Deny All 정책을 추가하는 모습을 보여주는 이미지.

빠르고 간단하지만, 정상적인 API 호출까지 모두 차단되므로 애플리케이션을 손쉽게 망가뜨리는 방법이기도 합니다.

옵션 1: Deny All 정책을 적용해 애플리케이션 API 호출을 제한하는 모습을 보여주는 이미지.

기억하십시오. 우리의 목표는 정상적으로 실행 중인 애플리케이션을 중단시키지 않으면서 공격자를 차단하는 것입니다.

이런.

옵션 2: 세션 취소

AWS에는 활성 세션을 취소할 수 있는 유용한 기능이 있습니다. 콘솔에서 버튼 하나를 클릭하면, 버튼을 클릭한 시점 이전에 시작된 세션에 대해서만 접근을 거부하는 사용자 지정 Deny All 정책이 추가됩니다(이를 위한 단순한 API 호출은 없지만, 동일한 동작을 하는 정책을 직접 작성하는 것은 어렵지 않습니다).

옵션 2: 세션을 취소하는 모습을 보여주는 이미지.

공격자가 새 세션을 침해하지 못하도록 차단했다고 가정하면, 이론상으로는 탈취된 자격 증명을 만료시켜 공격자를 차단하고 애플리케이션은 새 자격 증명으로 계속 동작하게 됩니다. 그런데…

옵션 1: Deny All 정책을 적용해 애플리케이션 API 호출을 제한하는 모습을 보여주는 이미지.

아닙니다. 두 번째 실패입니다. 왜일까요?

IMDS는 자격 증명이 만료될 때만 이를 갱신합니다. IMDS는 IAM과는 별개의 서비스이며, 자격 증명이 취소되었다는 사실을 알지 못하고 새 자격 증명을 가져와 인스턴스에 제공할 이유도 동기도 없습니다. 세션이 끝날 때까지 취소된 자격 증명을 계속 제공합니다.

옵션 3: IAM 역할 변경 후 기존 역할 거부

이제 좀 더 정교한 방법으로 넘어갑니다. 새 역할을 만들어 인스턴스가 이를 사용하도록 변경하고 기존 역할을 차단하면 어떨까요? 앞서와 마찬가지로, 공격자가 새 역할의 자격 증명까지 탈취할 수 없다는 것이 확실할 때만 유효한 방법입니다.

옵션 3: 기존 역할을 대체해 IAM 역할을 변경하는 모습을 보여주는 이미지.

아닙니다. 세 번째 실패입니다. 무슨 일이 벌어지고 있는 걸까요?

옵션 1: Deny All 정책을 적용해 애플리케이션 API 호출을 제한하는 모습을 보여주는 이미지.

대부분의 코드와 SDK는 시작 시 IAM 세션을 수립하고 메타데이터 서비스에서 자격 증명을 가져옵니다. 이 자격 증명에는 TTL(Time to Live)과 유사한 세션 지속 시간이 있습니다. 자격 증명은 메모리에 보관되며 지속 시간이 거의 끝날 때까지 사용됩니다. 예를 들어 이번 데모에서 사용한 Python의 Boto 라이브러리의 경우, 코드는 자격 증명 만료 15분 전이 되어야 새 자격 증명을 찾습니다.

따라서 애플리케이션은 갱신된 자격 증명을 찾기 전까지 계속 실패합니다. 설정 방식에 따라 다르지만 EC2 인스턴스에서는 기본적으로 6시간마다 이루어지는 경우가 많습니다. 물론 API 호출이 실패하면 새 자격 증명을 가져오도록 예외 처리를 훌륭하게 구현한 뛰어난 개발자가 있을 수도 있지만, 흔한 사용 사례가 아니므로 그럴 가능성은 낮습니다.

인스턴스 내부의 코드는 달리 알 방법이 없기 때문에 여전히 이전 역할을 사용하려고 시도합니다. 옵션 2에서는 IMDS가 IAM에 확인해 자격 증명을 갱신해야 한다는 것을 알지 못해 문제가 생겼습니다. 이번에는 코드가 IMDS와 통신해 새 자격 증명을 받아야 한다는 것을 알지 못하는 것입니다.

옵션 4: VPC 엔드포인트 삽입

이 방법은 제가 좀 더 정교하게 고안한 것으로, 단연 가장 복잡하지만 매우 효과적입니다. 모든 인스턴스는 AWS 내 가상 네트워크인 VPC(Virtual Private Cloud) 안에 존재합니다. 일반적으로 모든 API 호출은 인터넷을 거쳐 퍼블릭 AWS 엔드포인트에 도달합니다. 실제로 인터넷으로 나가는 경로가 없는 프라이빗 서브넷에 인스턴스가 있다면 해당 API 호출은 실패합니다.

그런데 자신의 프라이빗 인스턴스가 자신의 프라이빗 S3 버킷과 통신해야 한다면 이는 꽤 큰 문제입니다. 예전에는 인터넷 접근을 허용해야 했는데, 이는 비용이 발생할 뿐 아니라 보안 전문가들이 최소화하고자 하는 방식으로 노출 범위를 넓히는 일이었습니다.

Amazon의 해답이 바로 서비스 엔드포인트입니다. 이는 내부의 소프트웨어 정의 라우팅 구조로, VPC 내 리소스가 Amazon 내부 네트워크만을 통해 API 엔드포인트(그 외의 대상도 있지만 여기서 다룰 주제는 아닙니다)와 통신하도록 구성할 수 있습니다. 흥미로운 점은 VPC 엔드포인트를 사용하면 AWS가 프라이빗 헤더에 데이터를 담을 수 있게 되어 네트워크 트래픽에 추가적인 컨텍스트를 삽입하며, 이를 IAM 정책의 조건으로 활용할 수 있다는 것입니다.

먼저 인스턴스가 속한 서브넷에 S3용 VPC 엔드포인트를 추가합니다.

옵션 4: VPC 엔드포인트를 삽입하는 단계별 절차를 보여주는 이미지.

그런 다음 IAM 정책에 예상한 VPC에서 오지 않은 모든 트래픽을 거부하는 조건을 추가합니다. 교육 실습에서는 다음과 같이 구성합니다.

옵션 4: 예상한 VPC에서 오지 않은 트래픽을 거부하는 조건을 IAM 정책에 추가하는 모습을 보여주는 이미지.

이것이 제대로 동작하면 인스턴스에서의 API 호출은 계속 작동하지만, 해당 VPC 외부에서 사용된 자격 증명은 실패하게 됩니다(따라서 공격자가 같은 VPC 내 다른 리소스에 접근하지 못하기를 바라야 합니다).

옵션 4: 예상한 VPC에서 오지 않은 트래픽을 거부하는 IAM 정책 조건을 검증하는 모습을 보여주는 이미지.

성공입니다. 자격 증명은 VPC 내부에서만 작동하고 공격자는 차단됩니다. 앞서 언급한 Service Control Policy가 작동하는 방식이 바로 이와 똑같습니다. SCP의 문제는 서비스 엔드포인트가 비용과 복잡성을 더한다는 점, 그리고 필요한 엔드포인트를 모두 갖추지 않은 상태에서 해당 정책을 켜면 장애가 발생한다는 점입니다. 다만 이번에는 엔터프라이즈 규모로 발생합니다.

예상치 못한 동작

앞서 말씀드린 대로 이 실습은 약 2년 전에 만들었고 수백 명의 수강생이 이를 거쳤습니다. 지난주 Uptycs 의 Andre Rall이 저희 둘 다 참여하고 있는 클라우드 보안 커뮤니티에 다음과 같은 글을 올렸습니다(허가를 받아 인용합니다).

이런 동작이 정상인지 아시는 분 계신가요? 인스턴스에 연결된 인스턴스 프로파일에 역할을 붙여 두었습니다. (CLI를 통해) 인스턴스 프로파일에서 역할을 제거하되 인스턴스 프로파일은 인스턴스에 계속 연결된 상태로 두었는데, 인스턴스가 여전히 그 역할의 자격 증명을 사용할 수 있습니다. 상식적으로는 역할이 연결되어 있지 않으니 인스턴스가 이를 계속 사용할 수 없어야 할 것 같은데, 제가 놓친 부분이 있는 걸까요?

결국 여기서도 앞서 본 서비스 간 상호작용 문제가 다시 나타납니다. 내부적으로 인스턴스 프로파일은 AWS가 메타데이터 서비스에서 역할과 인스턴스를 연결하는 데 사용하는 수단입니다. Andre는 인스턴스 프로파일에서 역할을 제거했지만, 역할도 인스턴스 프로파일도 여전히 존재합니다.

IMDS가 자격 증명을 제공할 수 없을 것이라 생각하기 쉽지만, IMDS는 여전히 자격 증명을 보유하고 있으며 IAM 서비스에서 무슨 일이 있었는지 알지 못합니다. IMDS는 계속 자격 증명을 제공하고 역할은 여전히 그 자격 증명을 허용하므로 자격 증명은 계속 작동합니다. 이 경우에는 자격 증명 취소가 효과가 있습니다. 인스턴스 프로파일과 역할의 연결이 끊긴 후에는 IMDS가 새 자격 증명을 가져올 수 없기 때문입니다.

IAM 자격 증명 격리에는 고려할 세부 사항이 많으며, 여기서 다룬 것은 하나의 서비스(EC2)에 대한 예시 몇 가지에 불과합니다. 그러나 IAM 서비스가 IMDS와, IMDS가 SDK와 상호작용하는 흐름을 한번 파악하고 나면, 다른 상황에서도 활용할 수 있는 핵심 원칙에 대한 탄탄한 기반을 갖추게 될 것입니다.

그리고 최근 출시된 FireMon Cloud Defense 무료 요금제도 꼭 확인해 보십시오.

침해된 EC2 자격 증명 대응 방법 | FireMon