끄적이는 보송

[AWS] EC2 Metadata 관련하여 본문

STUDY/AWS

[AWS] EC2 Metadata 관련하여

끄적이는 보송 2022. 6. 28. 17:01
반응형

Instance Metadata (IMDS) 란

Instance Metadata란 실행 중인 인스턴스를 구성하거나 관리하는데 사용되는 인스턴스에 대한 데이터를 의미한다. 당연하게 EC2를 생성하고 생각 없이 사용해 왔지만 사실 EC2는 그저 가상화한 하드웨어의 조각일 뿐, 자신이 EC2인지 클라우드에 올라간 서버인지 모른다. EC2를 생성하게 되면 해당 EC2는 자동으로 Metadata와 연결되어 정보를 얻고, 서비스를 제공한다고 생각하면 된다.

EC2 생성 시, 디폴트로 생성하면 Metadata는 '선택'에 놓여있으며, 별도의 수정이 아니라면 해당 EC는 IMDS v1, v2를 모두 사용하게 된다. 아래 이미지는 EC2 생성 시, '고급 세부 정부'에서 확인할 수 있다.

Metadata와 Userdata를 헷갈릴 수 있어 추가 설명을 남기자면, Metadata는 EC2 Instance와 관련된 정보를 품고 있는 녀석이며, Userdata는 EC2 Instance가 실행하는 스크립트이다.

 

IMDS Version 확인

내가 사용하는 EC2의 IMDS Version을 확인하려면 아래 CLI 명령어로 EC2의 정보를 조회하면 알 수 있다.

$ aws ec2 describe-instances --region <region> --instance-id <instance-id> --query "Reservations[0].Instances[0].MetadataOptions"

각 IMDS Version 별로 결과물은 아래와 같다. 참고로 v1만 활성화는 없다.

#IMDS v1 & v2
{
    "State": "applied",
    "HttpEndpoint": "enable",
    "HttpTokens": "optional",
    "HttpPutResponseHopLimit": 1
}
#IMDS v2
{
    "State": "applied",
    "HttpEndpoint": "enabled",
    "HttpTokens": "required",
    "HttpPutResponseHopLimit": 1
}

 

IMDS v1 실습

EC2 Metadata를 조회해보려 한다. 참고로 Metadata 조회는 별도의 IAM Role 없이도, AWS EC2라면 모두 조회가 가능하며, 아래 curl 명령어로 입력하는 IP주소는 AWS의 Internal IP 주소로 EC2에서만 조회가 된다. 

http://169.254.169.254/latest/meta-data/

curl http://169.254.169.254/latest/meta-data/ 명령어를 치면 아래와 여러 가지 옵션과 함께 출력된다. 반드시 끝에 '/'를 붙이는 것을 잊지 말자. 옵션 끝에 '/'가 있다는 것은 그 뒤에 무언가 더 있다는 의미고, 그게 아니라면 Value라는 것을 의미한다.

어쩌면 Metadata 옵션에 'iam/'이 없을 수도 있다. 이 경우, EC2 인스턴스에 IAM Role이 부여되지 않은 것이므로, 해당 경로의 Metadata를 확인하고 싶으면 EC2에 Role 부여 후, 다시 확인해 보도록 하자. 그리고 Metadata에서 IAM Role 이름은 검색이 가능하지만, Policy는 검색이 불가능하다. (https://docs.aws.amazon.com/IAM/latest/UserGuide/troubleshoot_iam-ec2.html)

추가로 Secret Key와 Access Key를 EC2에 넣지 않고도 충분히 Metadata를 출력할 수 있다. 테스트한 서버는 어떤 자격증명 정보도 없다.

좀 더 다양한 정보를 위와 같이 출력해봤다. 이런 정보는 IAM Role 없이도 확인할 수 있으며 무료이다. 하지만 문제는 지금부터다. 만약 서버가 IAM Role이 할당되어 있는 상태이면, /iam/security-credentials/<role-name>을 조회하여 임시 자격증명을 발급받을 수 있다. 아래의 명령어로 내가 생성한 ec2-admin이라는 Role의 자격증명을 발급받았다. 자세히 보면, Access Key, Secret Key, Token, 그리고 만료 날짜도 보인다.

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/your_ec2_iam_role

이 정보를 이용해 외부인도 아래와 같이 해당 Role의 권한을 자유롭게 이용하여 AWS 내부 서비스에 접근할 수 있다. 아래의 예제는 위에 출력된 값을 입력하여, 내 AWS 계정의 S3 버킷 리스트를 출력한 결과다. 허가받지 않은 외부인이라면 좀 더 무서운 명령어를 입력할 수도 있어 보인다. (https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/id_credentials_temp_use-resources.html)

내 PC에서 AWS 접속

 

IMDS v2 실습

IMDS v1은 사용자가 EC2에 GET 요청을 전달할 수 있는 환경이라면, 누구든지 Metadata에 쉽게 접근할 수 있게 되며, 보안적으로 취약한 것은 사실이다. 그런 IMDS v1에 아래 추가 요소로 보안성이 개선된 것이 IMDS v2이다

- 사용자의 GET 요청 전, PUT 요청을 통해 Token을 받아야 한다.

- Hop Count를 지정할 수 있다. 기본으로 '1'로 설정되어 있으며, 일반적으로 Metadata Pakcet을 요청한 것이 EC2라면 Packet은 정상적으로 수신되어야 한다. 만약 EC2가 아닌 다른 곳이라면 Hop Count는 '1' 아니게 되며 데이터가 전송되지 않도록 구성할 수 있다. Hop Count값은 '"HttpPutResponseHopLimit": 1'을 통해 수정할 수 있다.

다음 명령어를 통해 토큰을 생성하고, 토큰을 이용해 Metadata를 불러올 수 있다. (https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html)

#토큰 생성
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
#토큰을 이용한 IAM Role 자격증명 받기
curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/<iam-role>
#위 두 명령어를 결합한 명령어
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` \
&& curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/<iam-role>

 

IMDS v1 비활성화 혹은 막기

실제로 보안 감사가 있어, IMDS v1이 문제가 될 수 있다. 이경우 해당 기능을 막아야 하는데 IMDS v2만 사용하도록 아래의 CLI 명령어로 v1을 비활성화할 수 있다. (https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html)

aws ec2 modify-instance-metadata-options \
    --region <region> \
    --instance-id <instance-id> \
    --http-tokens required \
    --http-endpoint enabled

혹은 아래 예제와 같이 MetadataHttpTokens를 반드시 요구하는 IAM 정책을 이용해 v2를 사용하도록 강제할 수 있다. 

{
	"Version": "2012-10-17"
	"Statement": [
		{
		"Effect": "Deny",
		"Action": "<action_tag>"
		"condition": {
			"StringNotEquals": {
				"ec2:MetadataHttpTokens": "required"
			}
		}
	}
	]
}
반응형
Comments