การทำ encrypt AWS Lambda Environment Variables ผ่าน AWS KMS
Tags: aws, awsthai, lambda, kms
Published: 2021-09-21 03:38:56

## สารบัญ (Table of Content)
1. [บทนำ](#intro)
2. [แผนผังของระบบ](#diagram)
3. [การประเมินราคาเบื้องต้น](#cost)
4. [ขั้นตอนที่ 1: สร้าง AWS Lambda Function](#step1)
5. [ขั้นตอนที่ 2: สร้าง CMK บน AWS Key Management Service (KMS)](#step2)
6. [ขั้นตอนที่ 3.1: ทำการ encrypt Lambda Environment Variables ผ่าน AWS Management Console](#step31)
7. [ขั้นตอนที่ 3.2: ทำการ encrypt Lambda Environment Variables ผ่าน AWS CloudFormation](#step32)
8. [ขั้นตอนที่ 3.3: ทำการ encrypt Lambda Environment Variables ผ่าน AWS Serverless Application Model (SAM)](#step33)
9. [ขั้นตอนที่ 4: ทดลองเข้าใช้งานบน IAM User อื่น](#step4)
10. [บทสรุป](#conclusion)

<a name="intro"></a>
## บทนำ
ในการใช้งาน AWS Lambda หลาย ๆ ครั้ง ผู้ใช้งานมักจะมีการเขียนข้อมูล parameter ที่ใช้ในการทำ Authetication กับระบบอื่น ๆ อย่าง Database Username/Password หรือ API Key บน Environment variables เพื่อให้ง่ายต่อการเรียกใช้งานหรือแก้ไข

แม้ว่าผู้ใช้งานจะมีการปกป้องข้อมูลเหล่านั้นด้วยการใช้ Secrets Key/Value Software อย่าง AWS Systems Manager Parameter Store หรือ AWS Secrets Manager บน template อย่าง AWS CloudFormation หรือ AWS Serverless Application Model (SAM) แต่อย่างไรก็ตาม เมื่อตัว AWS Lambda Function ถูก deploy ในระบบแล้ว จะพบว่าผู้ใช้งาน สามารถเข้าไปยังหน้า AWS Management Console แล้วมองเห็นค่าจริงบน Environment variables ได้อยู่ดี

ในบทความนี้ จะเป็นวิธีการนำ AWS Key Management Service (KMS) เข้ามาช่วยในการปกป้อง Environment variables ของ AWS Lambda ไม่ให้ผู้ใช้งานที่ไม่มีสิทธิในการเข้าถึงข้อมูลเหล่านี้ สามารถมองเห็นข้อมูลได้

<a name="diagram"></a>
## แผนผังของระบบ (Architecture Diagram)
![Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2owzm97avsqjq720ws7r.png)

<a name="cost"></a>
## การประเมินราคาเบื้องต้น (Cost Estimation)
* ราคาการเรียกใช้งาน Lambda - [AWS Lambda Pricing](https://aws.amazon.com/lambda/pricing/)
* ราคาการเรียกใช้งาน KMS - [AWS KMS Pricing](https://aws.amazon.com/kms/pricing/)

<a name="step1"></a>
## ขั้นตอนที่ 1: สร้าง AWS Lambda Function
* กรณีที่มีการใช้ AWS Lambda อยู่แล้ว สามารถใช้ตัวเดิมได้เลย
* เลือกตรวจสอบ Configuration -> Environment variables
![LambdaEnv](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0wylwr4krqdbtfqbmdwy.png)
    * โดยจะพบว่า ปกติแล้วจะมองเห็นค่า key/value ของ Environment variables ในลักษณะของ plain text เลย แม้ว่าจะมีการเขียน configuration ของ CloudFormation[1] หรือ Serverless Application Model (SAM)[2] ให้ทำการอ่านข้อมูลจาก AWS Systems Manager - Parameter Store หรือ AWS Secrets Manager ก็ตาม
    * ส่งผลให้เกิด security risk ที่เกิดขึ้นในระบบ โดยผู้ใช้งานอื่น ๆ สามารถเข้ามาดูข้อมูลใน AWS Lambda ได้ แม้ว่าจะมีการแยก IAM User ให้กับแต่ละผู้ใช้งานแล้วก็ตาม

<a name="step2"></a>
## ขั้นตอนที่ 2: สร้าง CMK บน AWS Key Management Service (KMS)
* ให้ทำการตรวจสอบ Lambda Execution Role จาก Configuration -> Permission
![LambdaRole](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0li6is5fvjph0oshnqq2.png)
* สร้าง CMK ด้วย การเลือก Symmetric Key
![Symmetric](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5lii0vsq34x43cruae9c.png)

* ตั้งชื่อให้กับ CMK Key
![CMK](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08nx05vey24hiho7g1le.png)

* เลือก key administrator (ในตัวอย่างเลือก IAM Role ของ account)
![KeyAdmin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i89mym46zfktt9sdae77.png)

* เลือก grant access ให้กับ IAM Role - โดยให้เลือกให้กับ Lambda Execution Role
![Keygrant](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yppjc7fyc2w258t204bk.png)

<a name="step31"></a>
## ขั้นตอนที่ 3.1: ทำการ encrypt Lambda Environment Variables ผ่าน AWS Management Console
* ไปที่ Lambda Function -> Configuration -> Environment variables แล้วเลือก "Edit" ที่ด้านขวาบน
* จากนั้นให้เลือก Encryption Configuration แล้วเลือก CMK ที่สร้างมา
![CMKEncrypt](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8x08w3iy80w880m7bmcq.png)

> :information_source:  หมายเหตุ: จะเห็นว่ามีอีก option ให้ผู้ใช้งานสามารถเลือก Encryption in transit ได้ โดยจะเป็นการ encrypt value ของ Environment variables ให้อยู่ในรูป BASE64 โดยต่อให้ผู้ใช้งานมีสิทธิมองเห็นค่าของ Environment variables ก็จะไม่สามารถดูเนื้อข้อมูลจริงได้ แต่การนำข้อมูลไปใช้งานต่อ ต้องทำการ decrypt ผ่าน CMK และ BASE64 ก่อนด้วย[3]

<a name="step32"></a>
## ขั้นตอนที่ 3.2: ทำการ encrypt Lambda Environment Variables ผ่าน AWS CloudFormation
* ตัวอย่าง AWS CloudFormation สำหรับ Lambda ที่ต้องใส่ให้ถูกต้องคือ "Role" และ "KmsKeyArn" (อย่าลืมแก้ไข AWS_ACCOUNT_ID)
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Lambda function demo
Resources:
  HelloworldCFN:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: HelloworldCFN
      Runtime: python3.9
      Role: arn:aws:iam::<AWS_ACCOUNT_ID>:role/service-role/HelloWorld-role-nj8898dr
      Handler: index.lambda_handler
      Code:
        ZipFile: |
          import json
          
          def lambda_handler(event, context):
          # TODO implement
          	return {
          	'statusCode': 200,
          	'body': json.dumps('Hello from Lambda!')
          	}
      Environment:
        Variables:
          db_user: nutcha
          db_pass: nutchapass
      KmsKeyArn: arn:aws:kms:ap-southeast-1:<AWS_ACCOUNT_ID>:key/f102024f-3ab8-4da9-8e80-13e163aa5cf9
```

> :warning: คำเตือน: ในการระบุ Environment variables ใน AWS CloudFormation ในการใช้งานจริง ควรใช้คู่กับ AWS Systems Manager - Parameter Store หรือ AWS Secrets Manager แทนการฝัง (hard coded) ตัว username และ password ไว้ใน template

<a name="step33"></a>
## ขั้นตอนที่ 3.3: ทำการ encrypt Lambda Environment Variables ผ่าน AWS Serverless Application Model (SAM)
* ตัวอย่าง AWS Serverless Application Model (SAM) สำหรับ Lambda ที่ต้องใส่ให้ถูกต้องคือ "Role" และ "KmsKeyArn" (อย่าลืมแก้ไข AWS_ACCOUNT_ID)
```yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Sample SAM Template for Lambda Helloworld
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloworldSAM
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Role: arn:aws:iam::<AWS_ACCOUNT_ID>:role/service-role/HelloWorld-role-nj8898dr
      KmsKeyArn: arn:aws:kms:ap-southeast-1:<AWS_ACCOUNT_ID>:key/f102024f-3ab8-4da9-8e80-13e163aa5cf9
      Environment:
        Variables:
          db_user: nutcha
          db_pass: nutchapass
```

> :warning: คำเตือน: ในการระบุ Environment variables ใน AWS Serverless Application Model (SAM) ในการใช้งานจริง ควรใช้คู่กับ AWS Systems Manager - Parameter Store หรือ AWS Secrets Manager แทนการฝัง (hard coded) ตัว username และ password ไว้ใน template

<a name="step4"></a>
## ขั้นตอนที่ 4: ทดลองเข้าใช้งานบน IAM User อื่น
* ทดลองเข้าใช้งาน IAM User อื่น ที่แม้มีสิทธิ "AWSLambda_FullAccess" ก็จะไม่สามารถมองเห็นข้อมูลได้
![LambdaAccess](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txrw1g8pur7yw7w1yw0o.png)

<a name="conclusion"></a>
## บทสรุป
ผู้ใช้งานสามารถทำการปกป้องข้อมูลใน Environment variables ของ AWS Lambda ได้โดยการใช้ CMK บน AWS KMS โดยเฉพาะผู้ที่มีสิทธิ์ถอดรหัส (decrypt) เท่านั้นที่จะสามารถมองเห็นค่าใน Environment variables บน AWS Management Console ได้

โดยการเข้ารหัส (encrypt) นั้น ผู้ใช้งานสามารถทำได้ทั้งผ่าน AWS Management Console, AWS CloudFormation และ AWS Serverless Application Model (SAM)

## แหล่งอ้างอิงอื่น ๆ
[1] https://aws.amazon.com/th/cloudformation/
[2] https://aws.amazon.com/serverless/sam/
[3] https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-encryption

![CastleArm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3pp3cc9du87hqg20ugb.jpg)