티스토리 뷰
[CIS AWS v1.3.0] 1.12 Ensure credentials unused for 90 days or greater are disabled
Turtle1000 2021. 2. 24. 23:02aws cli 버전 : aws-cli/2.1.11 Python/3.7.9 Windows/10 exe/AMD64 prompt/off
python 버전 : 3.8.5
CIS Benchmark 다운로드 링크 : www.cisecurity.org/blog/foundational-cloud-security-with-cis-benchmarks/
에드센스가 안붙네요.. 그래도 짬짬이 시간 들여서 포스팅하는데 뭔가 별론가 봅니다 흠..
암튼 이번 내용은 90일 이상 사용하지 않은 자격증명(password, access key)이 있는지 확인하는 내용입니다.
콘솔에서는 위와 같이 컬럼을 셋팅해서 확인 가능합니다.
Access Key ID 컬럼이 None이 아니고 Access key last used가 90 days 이상이면 취약이라고 보면 되겠죠? 패스워드는 현재 시간을 기준으로 Console last sign-in 시간을 비교해보면 될 것 같습니다.
또한 키 옆에 Inactive인 부분은 제거 대상으로, Active이지만 None인 경우도 검토 대상으로 보면 됩니다.
자격 증명 보고서는 이제 다들 뽑으실 것 같아서 이 복잡한(?) 조건을 풀어서 보시죠.
[password 관련 표]
user | password_enabled | password_last_used | 비고 |
<root_account> | not_supported | not_supported | 최근 기록 있으면 취약(password_last_used 참고) |
일반계정 | TRUE | YYYY-MM-DD~ | |
일반계정 | FALSE | YYYY-MM-DD~ | 활성화 시켰다가 비활성화한 경우 |
일반계정 | TRUE | N/A | 활성화는 했지만 로그인X |
일반계정 | FALSE | N/A |
사실 기준에서는 password_last_used 데이터가 없을 경우 password_last_changed 데이터를 통해서 점검을 하라고 되어있지만 본질적인 의미에서 봤을 때 password_last_used만 체크하는 것이 맞다고 생각합니다.(password_enabled가 TRUE인 경우만 점검 수행)
[access key 관련 표]
access_key_1_active | access_key_1_last_rotated | access_key_1_last_used_date | access_key_2_active | access_key_2_last_rotated | access_key_2_last_used_date | 비고 |
TRUE | YYYY-MM-DD~ | N/A | FALSE | N/A | N/A | |
TRUE | YYYY-MM-DD~ | YYYY-MM-DD~ | FALSE | YYYY-MM-DD~ | N/A | |
TRUE | YYYY-MM-DD~ | N/A | TRUE | YYYY-MM-DD~ | N/A |
access key 관련 표는 경우의 수가 너무 많아서(...) 이 정도만 작성하겠습니다. 나머지는 한 번 직접 써보세요. 그래야 실력이 늘고 학습이 됩니다.
중요한건 access_key_x_active가 TRUE면 무조건 rotated 값이 있어야 하고, FALSE 여도 rotated 값이 있을 수 있습니다.
이런 데이터들을 그냥 지나치면 안되고 항상 가정을 하셔야 합니다.
(잘못된 예시) access_key_x_active가 FALSE네 점검 안해도 된다 꿀이네 ㅋㅋ
(올바른 예시) access_key_x_active가 FALSE인데 rotated(또는 used_date) 값이 최근이네? (만약 보안담당자라면) 내가 비활성화(또는 활성화)한게 없는데 이거 좀 찾아봐야겠다. cloudtrail 로그에서 해당 사용자 계정 검색해봐야지(또는 SIEM 이던가 등등)
위와 같이 단순히 현상을 넘기지 말고 항상 어떤 상황일 때 어떻게 쓸 수 있을지 다각도로 생각해보고 가정을 해야 실제로 사고에 대한 대응이나 프로젝트를 하거나 응용을 하실 수가 있습니다.(물론 위와 같이 단순하지만은 않겠죠 당연히)
암튼 꼰대같은 소리는 그만하고 python으로 코딩하면,
은 내일로,.. 오늘 피곤하군요
---------- 210307 추가 ----------
여러가지로 큰 일들과 이후로 계속 대응하느라 너무 피곤해서 블로그를 진행하질 못했네요.
아래는 key1에 대한 코드입니다. 비슷하게 key2도 검증가능 할 것으로 보입니다.(최적화의 길은 항상 열려있습니다.)
import subprocess
import json
import base64
import maya
SEC = 1
MIN = 60 * SEC
HOUR = 60 * MIN
DAY = 24 * HOUR
MONTH = 30 * DAY
YEAR = 12 * MONTH
def get_string(b_obj, idx=0):
str_tmp = b_obj.decode()
# -1이 들어올 경우 전체 값 반환
if idx == -1:
return str_tmp.splitlines()
else:
return str_tmp.splitlines()[idx]
def get_json(b_obj):
str_tmp = b_obj.decode()
return json.loads(str_tmp)
def exec_cmd(tmp_cmd):
try:
tmp_data = subprocess.check_output(tmp_cmd, shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
error_msg = get_string(e.output, 1)
if 'NoSuchEntity' in error_msg:
aws_acct = [int(tmp) for tmp in error_msg.split(' ') if tmp.isdigit()]
print(f'[-] AWS ACCOUNT{aws_acct} has no password policy.')
elif 'GenerateCredentialReport' in error_msg:
print(f'[-] {error_msg}')
else:
print(error_msg)
return b'Error'
return tmp_data
if __name__ == '__main__':
cmd = (
'aws iam generate-credential-report '
'--query "State" --output text'
)
while True:
gcr_state = get_string(exec_cmd(cmd))
if gcr_state == 'COMPLETE':
print('[+] CREDENTIAL REPORT GENERATED!')
break
elif gcr_state == 'Error':
# print('[-] ERROR')
continue
else:
print('[*] CREDENTIAL REPORT GENERATING...')
cmd = (
'aws iam get-credential-report '
'--query "Content"'
)
gcr_result = get_string(base64.b64decode(exec_cmd(cmd)), -1)
del gcr_result[0]
current_time = maya.now().epoch
for gr in gcr_result:
tmp_data = gr.split(',')
user_id = tmp_data[0]
is_pw_enabled = tmp_data[3]
pw_last_used = tmp_data[4]
print()
if pw_last_used != 'N/A':
# print(maya.Datetime.today())
if current_time - maya.parse(pw_last_used).epoch < (MONTH * 3):
print(f'{user_id}\'s password safe.')
else:
print(f'{user_id}\'s password vuln.')
# get data about key1 & key2
is_key1_active, key1_last_rotated, key1_last_used = tmp_data[8:11]
is_key2_active, key2_last_rotated, key2_last_used = tmp_data[13:16]
# print(user_id, is_key1_active, key1_last_rotated, key1_last_used)
# print(user_id, is_key2_active, key2_last_rotated, key2_last_used)
if is_key1_active == 'false' and key1_last_rotated == 'N/A' and key1_last_used == 'N/A':
print(f'{user_id}\'s key1 safe.')
continue
elif is_key1_active == 'true' and key1_last_used != 'N/A':
if current_time - maya.parse(key1_last_used).epoch < (MONTH * 3):
print(f'{user_id}\'s key1 safe.')
else:
print(f'{user_id}\'s key1 vuln.')
elif is_key1_active == 'true' and key1_last_used == 'N/A':
if current_time - maya.parse(key1_last_rotated).epoch < (MONTH * 3):
print(f'{user_id}\'s key1 safe.')
else:
print(f'{user_id}\'s key1 vuln.')
else:
print(f'{user_id} review required.')
아래는 실제 출력 결과입니다.
만지다가 너무 오랜만에 좀 수정하고 실행하니 부족한 부분이 많네요.
비밀번호 없으면 출력해주는 기능이라던가 이런 것들은 추가하셔서 사용하시면 될 것 같습니다~
감사합니다.
'퍼블릭클라우드 > AWS' 카테고리의 다른 글
- Total
- Today
- Yesterday
- platform
- JavaScript
- web
- conftest policy
- .get()
- 우주와컴퓨터
- 4xx
- opensource
- steampipe
- cloudsecurity
- defaulttheme
- teplate
- IAM
- 2xx
- terraform
- REACT
- scp
- AWS #CIS
- aws
- security
- CIS
- temlate
- stateType
- ControlTower
- Cloud
- compliance
- fleet manager
- ViaAWSService
- 계정정보저장
- findinglatestversion
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |