by James Beswick | on 28 OCT 2021 | in AWS Lambda, AWS Secrets Manager, Serverless | Permalink | Share
Bài viết này được viết bởi Andy Hall, Senior Solutions Architect.
Các lớp và tiện ích của AWS Lambda được sử dụng bởi các nhà cung cấp phần mềm bên thứ ba để giám sát các chức năng Lambda. Một giải pháp giám sát cần các biến môi trường để cung cấp thông tin cấu hình để gửi thông tin về các số liệu đến một điểm cuối.
Quản lý thông tin này dưới dạng biến môi trường qua hàng nghìn hàm Lambda tạo ra chi phí quản lý. Thay vào đó, bạn có thể sử dụng phương pháp trong bài viết blog này để tạo các biến môi trường động từ thông tin được lưu trữ trong AWS Secrets Manager.
Điều này có thể giúp tránh việc quản lý việc xoay vòng bí mật cho từng hàm riêng lẻ. Nó đảm bảo rằng các giá trị được mã hóa đến runtime và ẩn đi việc quản lý các biến môi trường.
Tổng quan
Bài viết này hướng dẫn cách tạo một lớp Lambda cho các runtime Node.js, Python, Ruby, Java và .NET Core. Nó lấy các giá trị từ Secrets Manager và chuyển đổi bí mật thành một biến môi trường có thể được sử dụng bởi các lớp và chức năng khác. Lớp Lambda sử dụng một wrapper script để lấy thông tin từ Secrets Manager và tạo các biến môi trường.
Các bước trong quá trình như sau:
- Dịch vụ Lambda phản hồi một sự kiện và khởi tạo Lambda context.
- Wrapper script được gọi là một phần của giai đoạn khởi tạo Lambda.
- Wrapper script gọi một tập lệnh Golang và truyền vào ARN của bí mật để lấy thông tin.
- Tập lệnh Golang sử dụng API Secrets Manager để lấy bí mật đã được giải mã.
- Wrapper script chuyển đổi thông tin thành các biến môi trường và gọi bước tiếp theo trong quá trình xử lý.
Toàn bộ mã cho bài viết này có sẵn từ GitHub repo này.
Wrapper script
Kịch bản bọc là điểm vào chính cho tiện ích và được gọi bởi dịch vụ Lambda như một phần của giai đoạn khởi tạo. Trong giai đoạn này, kịch bản bọc sẽ đọc thông tin cơ bản từ môi trường và gọi tập lệnh Golang. Nếu có vấn đề với tập lệnh Golang, kịch bản bọc sẽ ghi lại một tuyên bố và thoát với lỗi.
| # Get the secret value by calling the Go executable values=$(${fullPath}/go-retrieve-secret -r “${region}” -s “${secretArn}” -a “${roleName}” -t ${timeout}) last_cmd=$? # Verify that the last command was successful if [[ ${last_cmd} -ne 0 ]]; then echo “Failed to setup environment for Secret ${secretArn}” exit 1 fi |
Tập lệnh Golang
Điều này sử dụng Golang để gọi các API của AWS vì môi trường thực thi Lambda không cung cấp giao diện dòng lệnh AWS Command Line Interface một cách tự nhiên. Tập lệnh Golang có thể được bao gồm trong một lớp để lớp đó hoạt động với một số runtime của Lambda.
Tập lệnh Golang chụp và xác nhận các đối số dòng lệnh để đảm bảo rằng các tham số cần thiết được cung cấp. Nếu Lambda không có quyền để đọc và giải mã bí mật, bạn có thể cung cấp một ARN cho một vai trò để giả mạo.
Đoạn mã ví dụ sau cho thấy cách tập lệnh Golang lấy thông tin cần thiết để giả mạo một vai trò bằng cách sử dụng AWS Security Token Service
| client := sts.NewFromConfig(cfg) return client.AssumeRole(ctx, &sts.AssumeRoleInput{ RoleArn: &roleArn, RoleSessionName: &sessionName, }, ) |
Sau khi có được các quyền cần thiết, bí mật có thể được lấy bằng cách sử dụng API của Secrets Manager. Đoạn mã ví dụ sau sử dụng các thông tin đăng nhập mới để tạo kết nối khách hàng tới Secrets Manager và bí mật:
| client := secretsmanager.NewFromConfig(cfg, func(o *secretsmanager.Options) { o.Credentials = aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(*assumedRole.Credentials.AccessKeyId, *assumedRole.Credentials.SecretAccessKey, *assumedRole.Credentials.SessionToken)) }) return client.GetSecretValue(ctx, &secretsmanager.GetSecretValueInput{ SecretId: aws.String(secretArn), }) |
Sau khi lấy được bí mật, nội dung phải được chuyển đổi thành một định dạng mà kịch bản bọc có thể sử dụng. Đoạn mã mẫu dưới đây mô tả quá trình chuyển đổi từ một chuỗi bí mật thành JSON bằng cách lưu trữ dữ liệu trong một bản đồ. Khi dữ liệu được lưu trong một bản đồ, một vòng lặp được sử dụng để đầu ra thông tin dưới dạng các cặpnkey-value.
| // Convert the secret into JSON var dat map[string]interface{} // Convert the secret to JSON if err := json.Unmarshal([]byte(*result.SecretString), &dat); err != nil { fmt.Println(“Failed to convert Secret to JSON”) fmt.Println(err) panic(err) } // Get the secret value and dump the output in a manner that a shell script can read the // data from the output for key, value := range dat { fmt.Printf(“%s|%s\n”, key, value) } |
Chuyển đổi thành các biến môi trường
| # Read the data line by line and export the data as key value pairs # and environmental variables echo “${values}” | while read -r line; do # Split the line into a key and value ARRY=(${line//|/ }) # Capture the kay value key=”${ARRY[0]}” # Since the key had been captured, no need to keep it in the array unset ARRY[0] # Join the other parts of the array into a single value. There is a chance that # The split man have broken the data into multiple values. This will force the # data to be rejoined. value=”${ARRY[@]}” # Save as an env var to the temp file for later processing echo “export ${key}=\”${value}\”” >> ${tempFile} done # Source the temp file to read in the env vars . ${tempFile} |
Tại điểm này, thông tin được lưu trữ trong bí mật hiện đã sẵn có dưới dạng các biến môi trường cho các lớp và Lambda function.
Triển khai
Để triển khai giải pháp này, bạn phải xây dựng trên một phiên bản đang chạy trên Amazon Linux 2 AMI. Điều này đảm bảo rằng tập lệnh Golang đã biên dịch sẽ tương thích với môi trường thực thi Lambda.
Để triển khai, chạy:
./build.sh <ARN of the secret to use>
Sau khi quá trình xây dựng hoàn thành, các tài nguyên sau sẽ được triển khai vào tài khoản AWS của bạn:
- Một lớp Lambda (được gọi là get-secrets-layer)
- Một lớp Lambda thứ hai để kiểm tra (được gọi là second-example-layer)
- Một hàm Lambda (được gọi là example-get-secrets-lambda)
Kiểm thử
Để kiểm tra việc triển khai, tạo một sự kiện kiểm thử để gửi đến hàm Lambda mới example-get-secrets-lambda bằng cách sử dụng Bảng điều khiển Quản lý AWS. Hàm Lambda kiểm thử sử dụng cả hai lớp Lambda get-secrets-layer và second-example-layer, và bí mật được chỉ định từ quá trình xây dựng. Hàm này đăng nhập các giá trị của các biến môi trường đã được tạo ra bởi các lớp get-secrets-layer và second-example-layer:
The secret contains the following information:
| { “EXAMPLE_CONNECTION_TOKEN”: “EXAMPLE AUTH TOKEN”, “EXAMPLE_CLUSTER_ID”: “EXAMPLE CLUSTER ID”, “EXAMPLE_CONNECTION_URL”: “EXAMPLE CONNECTION URL”, “EXAMPLE_TENANT”: “EXAMPLE TENANT”, “AWS_LAMBDA_EXEC_WRAPPER”: “/opt/second-example-layer” } |
Đây là mã Python cho hàm example-get-secrets-lambda:
| import os import json import sys def lambda_handler(event, context): print(f”Got event in main lambda [{event}]”,flush=True) # Return all of the data return { ‘statusCode’: 200, ‘layer’: { ‘EXAMPLE_AUTH_TOKEN’: os.environ.get(‘EXAMPLE_AUTH_TOKEN’, ‘Not Set’), ‘EXAMPLE_CLUSTER_ID’: os.environ.get(‘EXAMPLE_CLUSTER_ID’, ‘Not Set’), ‘EXAMPLE_CONNECTION_URL’: os.environ.get(‘EXAMPLE_CONNECTION_URL’, ‘Not Set’), ‘EXAMPLE_TENANT’: os.environ.get(‘EXAMPLE_TENANT’, ‘Not Set’), ‘AWS_LAMBDA_EXEC_WRAPPER’: os.environ.get(‘AWS_LAMBDA_EXEC_WRAPPER’, ‘Not Set’) }, ‘secondLayer’: { ‘SECOND_LAYER_EXECUTE’: os.environ.get(‘SECOND_LAYER_EXECUTE’, ‘Not Set’) } } |
Khi chạy một bài kiểm tra bằng cách sử dụng Bảng điều khiển Quản lý AWS, bạn sẽ thấy phản hồi sau được trả về từ Lambda trong Bảng điều khiển Quản lý AWS:
| { “statusCode”: 200, “layer”: { “EXAMPLE_AUTH_TOKEN”: “EXAMPLE AUTH TOKEN”, “EXAMPLE_CLUSTER_ID”: “EXAMPLE CLUSTER ID”, “EXAMPLE_CONNECTION_URL”: “EXAMPLE CONNECTION URL”, “EXAMPLE_TENANT”: “EXAMPLE TENANT”, “AWS_LAMBDA_EXEC_WRAPPER”: “/opt/second-example-layer” }, “secondLayer”: { “SECOND_LAYER_EXECUTE”: “true” } } |
Khi bí mật thay đổi, có một khoảng trễ trước khi những thay đổi đó sẵn có cho các lớp và chức năng Lambda. Điều này xảy ra vì lớp chỉ thực thi trong giai đoạn khởi tạo của vòng đời Lambda. Sau khi môi trường thực thi Lambda được tạo lại và khởi tạo, lớp sẽ thực thi và tạo ra các biến môi trường với thông tin bí mật mới.
Kết luận
Giải pháp này cung cấp một cách để chuyển đổi thông tin từ Secrets Manager thành các biến môi trường Lambda. Bằng cách tiếp cận này, bạn có thể tập trung quản lý thông tin thông qua Secrets Manager, thay vì ở mức độ chức năng.
Để biết thêm thông tin về vòng đời thực thi Lambda, vui lòng xem tài liệu về Lambda execution environment lifecycle.
Mã nguồn cho bài viết này có sẵn từ GitHub repo này.
Để biết thêm tài nguyên học tập về serverless, hãy ghé thăm Serverless Land.