在很多场景中,您需要使用凭据,令牌,API密钥等来访问某些服务。例如,您需要使用数据库口令来访问业务的某些数据库。但是,将它们作为纯文本文档存储在代码中是一个重大的安全漏洞。任何有权访问您的代码库的人都可以读取这些机密,并未经授权访问您的数据库执行恶意操作。
什么是AWS Secrets Manager?
此服务允许您轻松轮换、管理和检索口令,比如数据库凭据、API密钥、AWS credentials。可以通过控制台、API、CLI检索口令,不需要以纯文本形式对敏感信息硬编码在代码或者配置文件中。此外,可以通过IAM进行细粒度的权限控制,集中审核AWS云、第三方服务和本地资源的密钥轮换。口令可以轻松复制到其他区域。
更多详情。
第一步:创建和保存口令
您可以通过控制台或者CLI创建口令。如果配合AWS云原生的数据库,比如RDS、DocumentDB、Redshift cluster。可以选择自动轮换密钥,选择后通过Cloud Formation将自动创建能够执行自动轮换的Lamdba,以及对应的权限赋予这个Lamdba。
如果要保存非AWS托管的云原生数据库,或者其他的口令可以通过下面的操作完成:
创建密钥(控制台)
选择 Store a new secret (存储新密钥)。
在 Choose secret type(选择密钥类型)页面上,执行以下操作:
对于 Secret type(密钥类型),请选择 Other type of secret(其他密钥类型)。
以 Key/value pairs(键值对)或者 Plaintext(明文)格式输入密钥。一些示例:
API 密钥键值对:
ClientID
: my_client_id
ClientSecret
: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
凭证键值对:
Username
: saanvis
Password
: EXAMPLE-PASSWORD
数字证书
公有密钥明文:
-----BEGIN CERTIFICATE----- *EXAMPLE* -----END CERTIFICATE-----
私有密钥明文:
–---BEGIN PRIVATE KEY –-- *EXAMPLE* ––-- END PRIVATE KEY –---
c. 对于 Encryption key(加密密钥),选择 aws/secretsmanager 使用 Secrets Manager 的 Amazon 托管式密钥。使用此密钥不产生任何费用。例如,您还可以使用自己的客户管理型密钥来访问来自其他 Amazon Web Services 账户 的密钥。选择 Next (下一步)。
在 Choose secret type(选择密钥类型)页面上,执行以下操作:
输入一个描述性的 Secret name(密钥名称)和 Description(说明)。
在 Resource permissions(资源权限)中,可以先不配置。
第二步:配置权限
管理员:负责管理口令,提供Secrets ID;
程序员:要使用RDS或者各类需要口令的场景时,请求管理员提供Secrets ID;
管理员的权限设置:添加policy,可以选择内置的policy: SecretsManagerReadWrite,建议增加condition条件限制访问来源,其中sourceIP替换为自己的IP段。然后将这个policy加在管理员的user或者role的权限集中:
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"secretsmanager:*",
"cloudformation:CreateChangeSet",
"cloudformation:DescribeChangeSet",
"cloudformation:DescribeStackResource",
"cloudformation:DescribeStacks",
"cloudformation:ExecuteChangeSet",
"ec2:DescribeSecurityGroups",
"ec2:DescribeSubnets",
"ec2:DescribeVpcs",
"kms:DescribeKey",
"kms:ListAliases",
"kms:ListKeys",
"lambda:ListFunctions",
"rds:DescribeDBClusters",
"rds:DescribeDBInstances",
"redshift:DescribeClusters",
"tag:GetResources"
],
"Effect": "Allow",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "true"
},
"IpAddress": {
"aws:SourceIp": "210.75.12.75/16"
}
}
},
{
"Action": [
"lambda:AddPermission",
"lambda:CreateFunction",
"lambda:GetFunction",
"lambda:InvokeFunction",
"lambda:UpdateFunctionConfiguration"
],
"Effect": "Allow",
"Resource": "arn:aws:lambda:*:*:function:SecretsManager*"
},
{
"Action": [
"serverlessrepo:CreateCloudFormationChangeSet",
"serverlessrepo:GetApplication"
],
"Effect": "Allow",
"Resource": "arn:aws:serverlessrepo:*:*:applications/SecretsManager*"
},
{
"Action": [
"s3:GetObject"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::awsserverlessrepo-changesets*",
"arn:aws:s3:::secrets-manager-rotation-apps-*/*"
]
}
]
}
程序员/程序获取secrets
获取secrets manager中的secrets需要添加指定哪个角色可以获取的policy,给指定的secrets ID:
Attach a permissions policy to an AWS Secrets Manager secret - AWS Secrets Manager (amazon.com)
控制台修改
打开控制台,找到AWS Secrets Manager;
选择需要修改权限策略的Secrets ID,点击进入详情页;
选择“编辑权限”;
如果secrets是通过AWS托管的密钥做的加密,则写入下面的策略,注意将role的arn替换成自己的。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/MyRole"
},
"Action": "secretsmanager:GetSecretValue",
"Resource": "*"
}
]
}
如果secrets使用了客户自主管理的AWS密钥进行的加密,则使用以下策略,也可以加condition,限制使用的前提条件:
{
"Version": "2012-10-17",
"Statement": [
{
"Principal": {
"AWS": "arn:aws:iam::000000000000:role/MyRole"
},
"Action": [
"secretsmanager:GetSecretValue",
"kms:Decrypt"
],
"Effect": "Allow"
}
]
}
000000000000
是你的 AWS account ID, us-east-1
是 AWS region code 以及 mySecretID
是secrete的ID,可以到控制台查看具体的ID。
AWS CLI的方法
执行下面的命令,其中secret ID替换为自己的:
aws secretsmanager get-resource-policy \\
--secret-id MyTestSecret
创建一个文件,mypolicy.json里面写上允许哪个角色获取secret value.
然后执行下面的命令,其中secret ID替换为自己的,文件地址替换为刚才创建好的mypolicy.json的路径:
aws secretsmanager put-resource-policy \\
--secret-id MyTestSecret \\
--resource-policy file://mypolicy.json \\
--block-public-policy
第三步:代码中使用secrets manager
以请求访问数据库为例,未使用secrets manager的时候,IP地址、端口号、用户名和密码直接写在代码里。
更多连接方式参见:Connect to a SQL database with credentials in an AWS Secrets Manager secret - AWS Secrets Manager (amazon.com)
为了节约调用次数产生的费用,还可以使用缓存功能,支持java、python、.net、go写的程序使用缓存功能。以java编码为例:如何在JAVA应用中缓存AWS Secrets Manager安全凭据;默认1小时刷新获取一次secrets,可以重新设定默认的刷新时间。
以python代码为例,数据库的IP地址,端口号,用户名和密码都是从secrets manager获取的,而不是直接明文写在代码中:
import botocore
import botocore.session
import jaydebeapi
import json
from aws_secretsmanager_caching import SecretCache, SecretCacheConfig
client = botocore.session.get_session().create_client('secretsmanager')
cache_config = SecretCacheConfig()
cache = SecretCache( config = cache_config, client = client)
secret = cache.get_secret_string('test/mysql')
json_object = json.loads(secret)
host = json_object["host"]
port = json_object["port"]
jdbc_url="jdbc:mysql://" + host + ":" + port
user = json_object["username"]
pwd = json_object["password"]
driver = "com.mysql.jdbc.Driver"
jar_file = './mysql-connector-java-5.1.34.jar'
sql = 'select * from table_name'
connect = jaydebeapi.connect(driver, jdbc_url, [user, pwd], jar_file)
connect.close
配置文件中如何使用?
如果是通过yml格式的配置文件连接数据库,则类似以下代码:
server:
port: 8080
ervlet:
context-path: /
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
如果使用secrets manager,则如下:
首先,安装依赖 dependency,不同的配置文件需要的依赖不同,详细可以参考此文档。
以使用workato进行配置管理为例,在配置文件中,添加一个secrets
部分,带上 provider
和 region
:
可参见详细文档
secrets:
provider: aws
region: <YOUR_REGION>
如果是连接数据库,可以在配置文件中写入:
database:
sales_database:
adapter: sqlserver
host: localhost
port: 1433
database: test
username: sales_user
password: { secret: '<SECRET_NAME>' }
其他有用的blog: