[更新]
我不知道为什么这个问题被标记为关闭,这对我来说似乎是一个常见的情况,几乎所有我见过和我知道的密码都以纯文本形式存储在秘密存储中(AWS Secret Manager,Hashicorp Vault ...ecc)供应用程序在各种场景中使用,例如数据库连接等。在本地加密密码将迫使我跟踪其他存储中的纯文本密码(在我看来,在 1Password 中......无论任何地方),并打破其他常见做法,例如自动密码轮换。
[问题]
我有一个受密码保护的个人 Jupyter Notebook,在使用 Terraform 构建的 AWS Linux EC2 实例上运行。
在创建实例时,我在 AWS 秘密管理器中创建并存储秘密密码,以便稍后在
user_data
中检索并将其保存在 jupyter_notebook_config.py
中:
echo "c.ServerApp.password = u'$(aws secretsmanager get-secret-value --secret-id ${aws_secretsmanager_secret.jupyter.arn} --query SecretString --output text)'" >> /home/ec2-user/.jupyter/jupyter_notebook_config.py
它可以工作,缺点是我必须先对密钥进行氩加密,然后才能将其存储在 AWS Secrets Manager 中。
因此,我正在寻找一种方法,将其以纯文本形式存储在 AWS 秘密管理器中,并在保存到 Jupyter 配置文件之前在两者之间放置一些本地加密机制。 理想的新脚本是:
PLAIN_PWD=$(aws secretsmanager get-secret-value --secret-id ${aws_secretsmanager_secret.jupyter.arn} --query SecretString --output text)
ARGON_HASHED_PWD=some-existing-linux-function($PLAIN_PWD)
echo "c.ServerApp.password = u'$(ARGON_HASHED_PWD)'" >> /home/ec2-user/.jupyter/jupyter_notebook_config.py
其中
some-existing-linux-function
已经存在或者可以使用包管理器(即 yum)安装。
特别是 Jupiter 中已经提供了用于散列密码的实用程序,但不幸的是它需要手动干预,例如密码确认。
这是此类实用程序的一个片段:
import hashlib
from random import random
import argon2
# ......
if algorithm == "argon2":
ph = argon2.PasswordHasher(
memory_cost=10240,
time_cost=10,
parallelism=8,
)
h_ph = ph.hash(passphrase)
return ":".join((algorithm, h_ph))
最后,我决定暂时不要搞乱 EC2 和安装 argon2 的各种依赖项,因为它超出了我的知识范围。而且我可以在其他场景中重用该功能。例如,我有一个 EKS 和一个 ECS Jupyter 安装,也有同样的问题。
相反,我最终得到了一个 Python lambda 函数,它可以为我进行加密。
步骤如下:
先决条件
一个秘密和一个具有授予此类秘密权限的策略的角色。
1。 Lambda 层
准备包含 argon2 库的 Lambda 层。经过几次尝试后,我在 EC2 实例中运行此命令,因为我与 macOS 和本地 Linux VM 存在一些兼容性问题:
python3 -m venv argon2
source argon2/bin/activate
mkdir python # <- AWS requires everything inside a folder named 'python'
pip3 install cffi argon2-cffi argon2-cffi-bindings -t python
zip -r argon2-layer.zip python
2.创建图层
在 Lambda 控制台中,我创建了一个层来上传步骤 1 中创建的 zip 文件。
3. Lambda 函数
我在控制台中创建了这个 lambda 函数,分配了先决条件中提到的现有执行角色(作为个人规则,我不喜欢让 AWS 自动生成专用角色)。我没有花太多时间来构建可靠的用例,因为唯一的目的是检索我知道存在的单个秘密。这就是说,可以增强 lambda 函数以服务于更健壮的场景:
import json
import hashlib
from random import random
import argon2
import boto3
def lambda_handler(event, context):
if 'secret_name' in event:
secret_name = event['secret_name']
secret_value = retrieve_secret(secret_name)
return {
'statusCode': 200,
'body': json.dumps(passwd(secret_name))
}
else:
return {
'statusCode': 400,
'body': "secret missing"
}
def passwd(passphrase: str):
algorithm = "argon2"
ph = argon2.PasswordHasher(
memory_cost=10240,
time_cost=10,
parallelism=8,
)
h_ph = ph.hash(passphrase)
return ":".join((algorithm, h_ph))
def retrieve_secret(secret_name: str):
client = boto3.client('secretsmanager')
try:
response = client.get_secret_value(SecretId=secret_name)
secret_data = response['SecretString']
secret = json.loads(secret_data)
return secret
except Exception as e:
print("Error in retrieving secret:", e)
4。调用函数
此时,我上面发布的伪片段只是变成了 lambda 调用,就是这样:
ARGON_HASHED_PWD=some-existing-linux-function($PLAIN_PWD)
成为
ARGON_HASHED_PWD=$(aws lambda invoke --function-name encrypt-secret --payload '{"secret_name": "my/secret/pwd"}' .... lot of other parameter)