본문 바로가기
IT/Serverless

서버리스 AWS IAM Key 수명관리

by DOSGamer 2019. 8. 7.
반응형

목표시스템

AWS 계정관리에서 Access key 를 90일만 사용하도록 권장하고 있다

보안 때문이라도 90일 넘는 Access key 는 삭제하고 다시 새로운 Access key 를 만들어서 사용해야 한다

하지만, 사용자들은 Cli 로만 접근해서 사용한다면 90일 지났는지 알 수 없다

(AWS 콘솔로 들어가야지 확인가능하다)

그래서 람다로 스케쥴을 걸어서 매일 Access key 가 90일이 지난 사용자들이 있는 지 확인해서

90일이 지난 Access key 를 가지오 있는 사용자들에게 메시지를 보내서 알 수 있게 하려고 한다

사용하는기술

Javascript : 그냥 요즘 javascript 를 많이 쓰고 있어서

serverless framework : 서버리스 프레임워크 중에서 제일 맘에 들어서

lambda : aws 계정관리 이니 당연히 lambd

cloudwatch : cron 설정해서 매일 확인 또는 매주 확인 시키려고 함

VSCode : 에디터가 이거밖에 없다

dooray : 회사용 메신저 (잔디에서 바꿨다)

환경구성하기

Step 1. 개발할 폴더 만들고 VScode 에 project manager 로 등록

D:\workspace\monitoring-aws-iamkey

Step 2. node 프로젝트 초기설정

npm 초기세팅 해주고 author 추가

npm init -y

npm init -y

생성된

package.json 파일

 

 

Step 3. 필요한 node 패키지를 설치한다

필요한 패키지 설치해준다

개발할 때만 사용하는 패키지 설치

npm i -D aws-sdk

운영용으로도 사용하는 패키지 설치

npm i request

Step 4. serverless framework 설정파일을 만든다

serverless.yml 파일

해당 람다 함수가 user 이 List 와 Accesskey 의 List 를 조회하고

그리고, Inactive 된 AccessKey 를 삭제하니 DeleteAccessKey 권한을 부여합니다

  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "iam:ListUsers"
        - "iam:ListAccessKeys"
        - "iam:DeleteAccessKey"
      Resource:
        Fn::Join:
          - ":"
          - - "arn:aws:iam:"
            - Ref: AWS::AccountId
            - "user/*"

NOTE : serverless.yml 에서 변수를 다른 파일을 참조해서 읽어오도록 해봤습니다

DOORAYURL: ${file(./config/config.${self:provider.stage}.json):DOORAYURL}

config.dev.json 파일

{ "DOORAYURL" : "https://hook.dooray.com/services/DOORAY_WEBHOOK_URL" }

개발하기

Step 1. index.js 만들기

src 폴더 아래 index.js 파일 생성

 

 

설명

메인 함수는 searchUsers 입니다, event, context, callback 전부 사용하지 않아요.

module.exports.sendNotification = (event, context, callback) => {
    searchUsers();
};

searchUsers 는 전체 사용자 리스트를 불러오고

각 사용자별로 searchAccessKey 를 실행합니다

const searchUsers = () => {
    let params = {};
    iam.listUsers(params, function(err, data) {
        if (err) console.log(err, err.stack);
        for(var index = 0; index < data.Users.length; index++){
            searchAccessKey(data.Users[index].UserName);
        }
    });
};

 

searchAccessKey 는 사용자별로 2개까지 생성할 수 있는 AccessKey 를 불러와서

사용하지 않는 AccessKey 는 삭제를 시키고

90일이 지난 AccessKey 는 메시지를 보냅니다

const searchAccessKey = (userName) => {
    let params = { UserName : userName };
    iam.listAccessKeys(params, function(err, data) {
        if (err) console.log(err, err.stack);
        else {
            for(let index=0; index < data.AccessKeyMetadata.length; index++){
                if (isInActivateKey(data.AccessKeyMetadata[index])) {
                    deleteKey(userName, data.AccessKeyMetadata[index].AccessKeyId);
                }
                if (isExpiredKey(data.AccessKeyMetadata[index])) {
                    sendMessage(userName, data.AccessKeyMetadata[index]);
                }
            }
        }
    });
};

sendMessage 는 두레이 메신저로 보낼 수 있는 포멧으로 만들어서 request 로 보냅니다

const sendMessage = (userName, meta) => {
    let sendObj = {
        "botName": "AWS Bot",
        "botIconImage": "https://s3.ap-northeast-2.amazonaws.com/ICON_BUCKET/aws.png",
        "text": userName + "님 AWS Access Key 를 새로 생성해주세요",
        "attachments": [{
            "text": `${userName}님의 AccessKey가 생성된지 ${expirationPeriodDays}일이 지나서 보안에 위배되니 AWS Console 로 접속해서 새로 생성해주세요`,
            "color": "red"
        }]
    };
    
    let requestOptions = {
        uri : process.env.DOORAYURL,
        method: 'POST',
        headers : {
            'Content-Type': 'application/json'
        },
        body : JSON.stringify(sendObj).toString('utf8')
    };

    request(requestOptions, function(err, res, body) {
        if (err) console.log(err, err.stack);
        else console.log(res.statusCode);
    });

NOTE : 처음에는 동기형태로 async / await 로 만들어서 모든 사용자를 확인한 후에 메시지를 조합해서 1번만 보내는 걸로 만들었더니 실행시간 40초나 걸려서, 그냥 async 로 만들어서 따로 메시지를 보내는 방식으로 다시 바꿨습니다. 그랬더니 실행시간은 3~4초면 됨

Step 2. 테스트 하기

로컬PC에서 테스트 할 때 사용하는 테스트 파일

index.localtest.js

const lambda = require('../src/index');
const event = {};

lambda.sendNotification(event);

저는 로컬테스트 폴더를 만들어서 node 로 테스트 실행합니다

node localtest/index.localtest.js

Step 3. 배포하기

sls deploy -v --aws-profile AWS_ACCOUNT_ID

MFA 인증받은 ACCOUNT_ID 를 사용해서 배포합니다

--aws-profile 를 매번 써주기 싫으면

set AWS_PROFILE=AWS_ACCOUNT_ID

환경변수로 AWS_PROFILE 을 등록해놓습니다.

그러면 sls 가 알아서 AWS_PROFILE 을 참고해서 해당 계정을 사용합니다

함수만 재배포하기

sls deploy -v -f sendNotification --aws-profile AWS_ACCOUNT_ID

sendNotification 함수만 재배포 해줍니다.

실행결과

serverless.yml 파일에서 해당 람다함수를 매주 월요일 UTC 기준으로 0시니

대한민국시간으로 매주월요일 9시에 실행됩니다

    events:
      - schedule: cron(0 0 ? * MON *)

두레이 메신저의 내용

자원삭제하기

sls remove --aws-profile AWS_ACCOUNT_ID

cloudformation 이 실행되면서 관련된 자원들이 전부 삭제됩니다

 

참조사이트

https://github.com/NiteDesign/Lambda-IAM-Key-Rotation

 

NiteDesign/Lambda-IAM-Key-Rotation

Force AWS IAM access key rotation. Contribute to NiteDesign/Lambda-IAM-Key-Rotation development by creating an account on GitHub.

github.com

깃허브에 정리가 잘되어 있는 소스가 있어서 참고많이 했습니다

 

반응형