Total Pageviews

2024/06/10

[AWS Cloud Shell Error] eksctl: command not found

Problem

當我透過 CloudShell 執行 eksctl 指令出現以下錯誤訊息

[cloudshell-user@ip-10-138-162-6 ~]$ eksctl create cluster -f cluster.yaml 
-bash: eksctl: command not found


Root Cause

若在執行 eksctl 指令時出現 "command not found" 的錯誤,表示您還未安裝 eksctl

How-To

以下是安裝 eksctl 並解決這個問題的步驟:
以下是安裝 eksctl 並解決這個問題的步驟:
# 下載最新版本的 eksctl
[cloudshell-user@ip-10-138-162-6 ~]$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp

# 將可執行文件移動到 /usr/local/bin
[cloudshell-user@ip-10-138-162-6 ~]$ sudo mv /tmp/eksctl /usr/local/bin

# 驗證安裝
[cloudshell-user@ip-10-138-162-6 ~]$ eksctl version
0.182.0

# 執行結果
[cloudshell-user@ip-10-138-162-6 ~]$ eksctl create cluster -f cluster.yaml 
2024-06-10 06:15:21 []  eksctl version 0.182.0
2024-06-10 06:15:21 []  using region us-east-1
2024-06-10 06:15:21 []  skipping us-east-1e from selection because it doesn't support the following instance type(s): t3.micro
2024-06-10 06:15:21 [ℹ]  setting availability zones to [us-east-1c us-east-1b]
2024-06-10 06:15:21 [ℹ]  subnets for us-east-1c - public:10.0.0.0/19 private:10.0.64.0/19
2024-06-10 06:15:21 [ℹ]  subnets for us-east-1b - public:10.0.32.0/19 private:10.0.96.0/19
2024-06-10 06:15:21 [ℹ]  nodegroup "eks-node-group" will use "ami-0bcb49642ac49d5aa" [AmazonLinux2/1.24]
2024-06-10 06:15:21 [ℹ]  using Kubernetes version 1.24
2024-06-10 06:15:21 [ℹ]  creating EKS cluster "eks-acg" in "us-east-1" region with un-managed nodes
2024-06-10 06:15:21 [ℹ]  1 nodegroup (eks-node-group) was included (based on the include/exclude rules)
2024-06-10 06:15:21 [ℹ]  will create a CloudFormation stack for cluster itself and 1 nodegroup stack(s)
2024-06-10 06:15:21 [ℹ]  will create a CloudFormation stack for cluster itself and 0 managed nodegroup stack(s)
2024-06-10 06:15:21 [ℹ]  if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=us-east-1 --cluster=eks-acg'


2024/03/10

AWS Lambda Error:An error occurred (UnauthorizedOperation) when calling the AuthorizeSecurityGroupIngress operation: You are not authorized to perform this operation.

Problem

當我嘗試使用 Lambda function,增加一條 rule 至指定 security group 時,出現以下錯誤:

Test Event Name
MyTest

Response
null

Function Logs
START RequestId: 7f5624bf-430f-4c65-a51f-9060e990b159 Version: $LATEST
An error occurred (UnauthorizedOperation) when calling the AuthorizeSecurityGroupIngress operation: You are not authorized to perform this operation. User: arn:aws:sts::102832830373:assumed-role/AddSGFunction-role-shx93f9g/AddSGFunction is not authorized to perform: ec2:AuthorizeSecurityGroupIngress on resource: arn:aws:ec2:us-east-1:102832830373:security-group/sg-056a6d3af28d29d47 because no identity-based policy allows the ec2:AuthorizeSecurityGroupIngress action. Encoded authorization failure message: u7vWnAW1hpW1M7YZt5LVRybW3WXafRneSDK4jpCisbXWFiI5yS7DAZQBJNuXqUMKsRSSn-pTBiotcINMCxvnICsMzd9e7D61fZgGGwrrnrsSPcwnC6V-SH7pDmEtw_rD8cIHhN1CQIByIzn3waZ0bwQqB7ggufrlDZlf4pVWU860dhL89jes5EP8XAW-cuXnoz156F-11Us2ZToRlSHIFGbsTQhxCjaLTIkKFyLnd45mkgF_24a8VKjqUXz1jcEAfZEM3FgQeCoG7BBKqk9Z_3S-ODAPoBQ4NuGYFfYKTqIGOVx_QEV3HlqC9QEXJ1ylRWoZ2aU94KESR54ak4yk9U6bwZGMz_Y8Lxw2UcQBfI43sdvGQW8Ga6G8yGMLO9qjaFqgRkVBrUZIjpprl0vEo5pN96m8mzdmqdELDR0KUV69VZkLzfevef44zP2Bwo5JaQKhFyzb00eiaZj3AuLSbf7Hyzawp5DKnDa7xasZkHU60sVbDDPnAyWQ98D9felWps-tafPaWVO49rg50UQKAz2lSwDKFLT-BIluOph8ruuJO_0YZyiQJmn3TYMEq3x2uR7IUsYTdugmYAJzmzNHzdIy5YxBPGx7SEvoEX9C_xZIloJLSWkO
END RequestId: 7f5624bf-430f-4c65-a51f-9060e990b159
REPORT RequestId: 7f5624bf-430f-4c65-a51f-9060e990b159	Duration: 3407.09 ms	Billed Duration: 3408 ms	Memory Size: 128 MB	Max Memory Used: 89 MB	Init Duration: 408.87 ms

Request ID
7f5624bf-430f-4c65-a51f-9060e990b159


Root Cause

此 Lambda function 不具備增添 security group rule 的權限



How-To

增添以下權限 ec2:AuthorizeSecurityGroupIngress




Test Result

執行結果

Test Event Name
MyTest

Response
null

Function Logs
START RequestId: 266304a2-53ce-40f0-8918-7782fb6bb3cc Version: $LATEST
Ingress Successfully Set {'Return': True, 'SecurityGroupRules': [{'SecurityGroupRuleId': 'sgr-063e134cb604a00a2', 'GroupId': 'sg-056a6d3af28d29d47', 'GroupOwnerId': '102832830373', 'IsEgress': False, 'IpProtocol': 'tcp', 'FromPort': 80, 'ToPort': 80, 'CidrIpv4': '0.0.0.0/0'}], 'ResponseMetadata': {'RequestId': '58ea616d-28bb-4d65-b544-d61ff7834a33', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amzn-requestid': '58ea616d-28bb-4d65-b544-d61ff7834a33', 'cache-control': 'no-cache, no-store', 'strict-transport-security': 'max-age=31536000; includeSubDomains', 'content-type': 'text/xml;charset=UTF-8', 'content-length': '719', 'date': 'Sun, 10 Mar 2024 02:11:17 GMT', 'server': 'AmazonEC2'}, 'RetryAttempts': 0}}
END RequestId: 266304a2-53ce-40f0-8918-7782fb6bb3cc
REPORT RequestId: 266304a2-53ce-40f0-8918-7782fb6bb3cc	Duration: 3649.45 ms	Billed Duration: 3650 ms	Memory Size: 128 MB	Max Memory Used: 89 MB	Init Duration: 324.16 ms

Request ID
266304a2-53ce-40f0-8918-7782fb6bb3cc

確認 security group rule



延伸問題

若 Lambda function 要 revoke security group rule,需賦予以下權限,範例:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ec2:RevokeSecurityGroupIngress",
            "Resource": "arn:aws:ec2:region:account-id:security-group/sg-xxxxxxxx"
        }
    ]
}

實際例子:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "ec2:RevokeSecurityGroupIngress",
            "Resource": "arn:aws:ec2:us-east-1:102832830373:security-group/sg-056a6d3af28d29d47"
        }
    ]
}



2024/02/19

Using AWS CLI to Encrypt and Decrypt

上傳一個 plain text file 到 AWS CloudShell,並印出內容

[cloudshell-user@ip-10-130-78-240 ~]$ cat ExamplePlaintextFile.txt
abc
123
test

建立一個 AWS KMS Key 如下


透過 AWS CLI 加密原 plain text file,並產生一個 EncryptedFile.txt,並印出 EncryptedFile.txt 內容

[cloudshell-user@ip-10-130-78-240 ~]$ aws kms encrypt --key-id alias/AlbertKey --plaintext fileb://ExamplePlaintextFile.txt --output text --query CiphertextBlob | base64 --decode > EncryptedFile.txt
[cloudshell-user@ip-10-130-78-240 ~]$ cat EncryptedFile.txt
00Y0Tom%`He.08Ó~SGe`VCn5j0h     *H
             "N^";';P䫒}XU'Jڋ?oC


透過 AWS CLI 解密 EncryptedFile.txt 至 DecryptedFile.txt,並印出 DecryptedFile.txt

[cloudshell-user@ip-10-130-78-240 ~]$ aws kms decrypt --ciphertext-blob fileb://EncryptedFile.txt --output text --query Plaintext | base64 --decode > DecryptedFile.txt
[cloudshell-user@ip-10-130-78-240 ~]$ cat DecryptedFile.txt
abc
123
test


How to read Parameter Store values from Lambda function

已在 Parameter Store 建立兩個參數


已建立以下 Lambda function Code
import boto3
import json

def lambda_handler(event, context):
    # 初始化 SSM 客戶端
    ssm = boto3.client('ssm')
    
    # 參數名稱
    parameters_to_get = [
        '/Dev/DBServer/MySQL/db-user',
        '/Dev/DBServer/MySQL/db-pwd'
    ]
    
    # 從 Parameter Store 獲取參數值
    response = ssm.get_parameters(
        Names=parameters_to_get,
        WithDecryption=True  # 如果參數是加密的,設置為 True
    )
    
    # 初始化一個變數來存儲參數名稱和值
    parameters_values = {}
    
    # 檢查並讀取每個參數的值
    for param in response['Parameters']:
        parameters_values[param['Name']] = param['Value']
    
    # 列印參數值
    print(f"Parameter Values: {json.dumps(parameters_values)}")
    
    return {
        'statusCode': 200,
        'body': json.dumps(f"Parameter Values: {parameters_values}")
    }

賦予 Lambda 有讀取 SSM 的權限



執行結果

Test Event Name
MyTest

Response
{
  "statusCode": 200,
  "body": "\"Parameter Values: {'/Dev/DBServer/MySQL/db-pwd': 'mypassword', '/Dev/DBServer/MySQL/db-user': 'admin'}\""
}

Function Logs
START RequestId: 7c95489a-f09d-44b8-9b5e-25968ca0b318 Version: $LATEST
Parameter Values: {"/Dev/DBServer/MySQL/db-pwd": "mypassword", "/Dev/DBServer/MySQL/db-user": "admin"}
END RequestId: 7c95489a-f09d-44b8-9b5e-25968ca0b318
REPORT RequestId: 7c95489a-f09d-44b8-9b5e-25968ca0b318	Duration: 2379.66 ms	Billed Duration: 2380 ms	Memory Size: 128 MB	Max Memory Used: 78 MB	Init Duration: 301.53 ms

Request ID
7c95489a-f09d-44b8-9b5e-25968ca0b318


Create AWS Lambda from CloudFormation

假設已準備好 yaml file,內容如下:

AWSTemplateFormatVersion: '2010-09-09'
Description: 'AWS CloudFormation Sample: AWS Lambda Function with Python.'

Resources:
  HelloWorldFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.8
      Code:
        ZipFile: |
          def lambda_handler(event, context):
              return {
                  'statusCode': 200,
                  'body': 'Hello, World!'
              }
      Timeout: 5

  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: 'lambda-basic-execution'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'

確認 CloudFormation 執行結果



確認 CloudFormation 已建立的 AWS resources



確認所建立的 Lambda Function:



確認 Lambda 執行結果符合預期:

Test Event Name
Test

Response
{
  "statusCode": 200,
  "body": "Hello World!"
}

Function Logs
START RequestId: 665b5e07-c386-4b89-b59c-0a6e00979de0 Version: $LATEST
END RequestId: 665b5e07-c386-4b89-b59c-0a6e00979de0
REPORT RequestId: 665b5e07-c386-4b89-b59c-0a6e00979de0	Duration: 2.07 ms	Billed Duration: 3 ms	Memory Size: 128 MB	Max Memory Used: 39 MB	Init Duration: 129.94 ms

Request ID
665b5e07-c386-4b89-b59c-0a6e00979de0

AWS Lambda Alias

假設我有一支 Lambda function,內容如下:

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda! (Version 1)')
    }

並成功完成 Test:

Test Event Name
MyTest

Response
{
  "statusCode": 200,
  "body": "\"Hello from Lambda! (Version 1)\""
}

Function Logs
START RequestId: f0a719c8-1ffb-499d-942f-206f73dd0045 Version: $LATEST
END RequestId: f0a719c8-1ffb-499d-942f-206f73dd0045
REPORT RequestId: f0a719c8-1ffb-499d-942f-206f73dd0045	Duration: 11.58 ms	Billed Duration: 12 ms	Memory Size: 128 MB	Max Memory Used: 34 MB

Request ID
f0a719c8-1ffb-499d-942f-206f73dd0045


透過 AWS CLI 發佈第一個版本:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda publish-version --function-name HelloWorldFunction
{
    "FunctionName": "HelloWorldFunction",
    "FunctionArn": "arn:aws:lambda:us-east-1:827888540138:function:HelloWorldFunction:1",
    "Runtime": "python3.12",
    "Role": "arn:aws:iam::827888540138:role/service-role/HelloWorldFunction-role-2pj1z9b2",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 277,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2024-02-19T00:51:48.000+0000",
    "CodeSha256": "FGaiUQRyAxEPhQmLcV9dUlGl1qIvgba7Ae1zCInXC3g=",
    "Version": "1",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "d42bcc86-34a7-4ce4-a739-16e6d785c3af",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {
        "ApplyOn": "None",
        "OptimizationStatus": "Off"
:...skipping...


修改 Lambda function,程式內容如下:

import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda! (Version 2)')
    }


發佈第二個版本:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda publish-version --function-name HelloWorldFunction
{
    "FunctionName": "HelloWorldFunction",
    "FunctionArn": "arn:aws:lambda:us-east-1:827888540138:function:HelloWorldFunction:2",
    "Runtime": "python3.12",
    "Role": "arn:aws:iam::827888540138:role/service-role/HelloWorldFunction-role-2pj1z9b2",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 276,
    "Description": "",
    "Timeout": 3,
    "MemorySize": 128,
    "LastModified": "2024-02-19T01:02:46.000+0000",
    "CodeSha256": "xzDR5dGezW2VtWOvVraE1yY6kIQXIKy7UBS/1WDMeyw=",
    "Version": "2",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "299ba2c8-c055-4314-9b29-bbd9e9332e96",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip",
    "Architectures": [
        "x86_64"
    ],
    "EphemeralStorage": {
        "Size": 512
    },
    "SnapStart": {


建立 Alias,PROD 指向 Version 1、DEV 指向 Version 2

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda create-alias --function-name HelloWorldFunction --name PROD --function-version 1
{
    "AliasArn": "arn:aws:lambda:us-east-1:827888540138:function:HelloWorldFunction:PROD",
    "Name": "PROD",
    "FunctionVersion": "1",
    "Description": "",
    "RevisionId": "dfc0cdd9-5bf8-4483-bd0b-0cc098e4a70e"
}
[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda create-alias --function-name HelloWorldFunction --name DEV --function-version 2
{
    "AliasArn": "arn:aws:lambda:us-east-1:827888540138:function:HelloWorldFunction:DEV",
    "Name": "DEV",
    "FunctionVersion": "2",
    "Description": "",
    "RevisionId": "2526ec87-e93b-4189-828a-bab954fcf019"
}


執行 PROD alais,結果如下:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda invoke --function-name "HelloWorldFunction:PROD" outputfile.txt
{
    "StatusCode": 200,
    "ExecutedVersion": "1"
}


執行 DEV alais,結果如下:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda invoke --function-name "HelloWorldFunction:DEV" outputfile.txt
{
    "StatusCode": 200,
    "ExecutedVersion": "2"
}


Version 2 完成測試後,將 PROD 指向 Version 2:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda update-alias --function-name "HelloWorldFunction" --name "PROD" --function-version "2"
{
    "AliasArn": "arn:aws:lambda:us-east-1:827888540138:function:HelloWorldFunction:PROD",
    "Name": "PROD",
    "FunctionVersion": "2",
    "Description": "",
    "RevisionId": "9b3c5ce4-4c46-4bba-a5bf-ceb8291e090d"
}


執行 PROD alais,結果如下:

[cloudshell-user@ip-10-132-51-15 ~]$ aws lambda invoke --function-name "HelloWorldFunction:PROD" outputfile.txt
{
    "StatusCode": 200,
    "ExecutedVersion": "2"
}

2024/02/17

如何透過 AWS Lambda 啟動/關閉 EC2

前置作業

假設我已經建立好一台 EC2


已準備一支用 Python 語法寫的 AWS Lambda function(當 EC2 是 Running 狀態時,就 Stop 它;當 EC2 是 Stopped 狀態時,就 Start 它)

import boto3

# 初始化 EC2 客戶端
ec2 = boto3.client('ec2')

def lambda_handler(event, context):
    # 指定要操作的 EC2 實例 ID
    instance_id = 'i-0ebe0819d2efb0cff'

    # 獲取實例的當前狀態
    response = ec2.describe_instances(InstanceIds=[instance_id])
    state = response['Reservations'][0]['Instances'][0]['State']['Name']

    # 根據實例的當前狀態進行操作
    if state == 'running':
        # 如果實例正在運行,則停止它
        stop_response = ec2.stop_instances(InstanceIds=[instance_id])
        action = 'stopped'
    elif state == 'stopped':
        # 如果實例已停止,則啟動它
        start_response = ec2.start_instances(InstanceIds=[instance_id])
        action = 'started'
    else:
        # 如果實例處於其他狀態,不進行操作
        return {
            'statusCode': 400,
            'body': f'Instance {instance_id} is in {state} state, no action taken.'
        }

    # 返回操作結果
    return {
        'statusCode': 200,
        'body': f'Instance {instance_id} has been {action} successfully.'
    }

賦予 AWS Lambda 操作 EC2 的權限



執行測試:(Running => Stopped)

EC2 執行前


Lambda 執行結果


EC2 執行後



執行測試:(Stopped => Running)

EC2 執行前


Lambda 執行結果


EC2 執行後




2024/02/14

AWS S3 + CloudFront + OAI

步驟 1: Create S3 bucket


步驟 2: Upload a image file to  S3 bucket



步驟 3: Create CloudFront distribution 與使用 Origin Access Identity (OAI) 保護 S3 content




步驟 4: Update S3 bucket policy



步驟 5: 等候幾分鐘,待 CloudFront distribution 完成 Deploy



步驟 6: 測試 CloudFront distribution