使用 Hashicorp Vault 管理 SSH 访问
简介 SSH 提供对大多数企业/云供应商中类 Unix 服务器的安全访问。它用于连接到远程机器并在该远程机器上执行活动。要向某人提供 SSH 访问,需要共享远程主机的密码,或者需要将用户的 SSH 公钥添加到远程主机。当有太多用户和/或远程机器需要管理时,这会成为一个问题。 通过本教程,我们将通过开始了解与传统方法相关的问题以及如何利用 SSH 架构来探索如何使用Hashicorp Vault管理
简介
SSH 提供对大多数企业/云供应商中类 Unix 服务器的安全访问。它用于连接到远程机器并在该远程机器上执行活动。要向某人提供 SSH 访问,需要共享远程主机的密码,或者需要将用户的 SSH 公钥添加到远程主机。当有太多用户和/或远程机器需要管理时,这会成为一个问题。
通过本教程,我们将通过开始了解与传统方法相关的问题以及如何利用 SSH 架构来探索如何使用Hashicorp Vault管理 SSH 访问。
传统做法的问题
管理 SSH 访问的传统方法存在一系列关键问题,例如:
-
为所有机器创建安全密码并安全地存储/共享它们是乏味的。更不用说密码的轮换了。
-
必须将每个用户的 SSH 密钥添加到所有远程机器。管理的钥匙太多了!如果用户离开团队怎么办?他们的密钥应该从所有远程机器上移除。要将新用户添加到团队中,需要将他们的密钥添加到他们打算访问的所有远程机器上,这意味着密切关注访问要求。
-
跨多个系统和云环境一致地管理密钥是复杂的。
解决上述问题的一个更好的方法是结合使用 Hashicorp Vault 和 SSH 证书身份验证。该架构旨在解决上述问题以及以下功能/结果:
-
启用基于身份的访问,用户应该在被授予通过 SSH 连接到远程计算机的能力之前进行身份验证。
-
用于 SSH 访问的基于角色的访问控制 (RBAC),其中可以为用户分配主机上的不同权限。
-
寿命较短的 SSH 凭证。
-
可与大量用户以及分布在不同企业的多台机器很好地扩展。
SSH证书认证
如果您知道 SSL(安全套接字层)证书的工作原理,那么 SSH 证书的工作方式与它们类似。 SSH 证书只是由称为证书颁发机构 (CA) 的受信任实体使用其私钥签名的公钥。 SSH 证书仅在一段时间内有效,类似于 SSL 证书。如果它们过期了,那么它们就不能再使用了。
SSH 协议实现带有许多配置选项,但通常这些配置并不常用。我们在这里使用的一种配置是 sshdAuthorizedPrincipalsFile。
Hashicorp Vault
HashiCorp Vault 是一个基于身份的秘密和加密管理系统。机密是您希望严格控制访问的任何内容,例如 API 加密密钥、密码和证书。 Vault 提供由身份验证和授权方法控制的加密服务。
Vault 提供不同类型的秘密引擎,如通用键值对、PKI 证书、Cloud IAM 等。该架构将使用SSH 秘密引擎,使其能够作为我们受信任的 SSH CA。
架构
上图中的数字代表以下步骤:
-
用户创建个人 SSH 密钥对。
-
用户使用 OIDC 凭据向 Vault 进行身份验证(Vault 也提供其他身份验证方法)。
-
通过身份验证后,用户将其 SSH 公钥发送到 Vault 进行签名。
-
Vault 对 SSH 密钥进行签名,并将 SSH 证书返回给用户。
-
用户使用 SSH 证书发起 SSH 连接。
-
远程主机验证客户端 SSH 证书是否由受信任的 SSH CA 签名并允许连接。
可以有多个具有权限级别的保管库角色。因此,SSH 证书可以根据 Vault 角色使用不同的参数和原则进行签名。一旦用户成功验证了 Vault,将动态生成一个 Vault 令牌,并附带一个策略,该策略指示用户可以访问哪些服务和机密。
先决条件
-
已安装 Kubernetes 集群和 helm。
-
要在您的保管库服务器上启用 Google 的 OIDC 身份验证,请按照以下步骤操作
-
我们将使用 Google 作为 Oath2 提供者。按照这个文档创建 Oath2 凭证。
-
具有超级管理员角色的 G-suite 帐户,用于在 Google 工作区中执行域范围委派权限。
-
上一步获取的Serviceaccount。
-
如果要使用 GCP 启用 Vault 自动解封,请在 GCP 中创建密钥环和加密密钥。为简单起见,您可以从 GCP 为
read key_ring
和crypto_key
创建一个新的服务帐户。我为启用域范围授权时创建的服务帐户添加了权限()。
保险柜安装
我们将使用 helm 在集群上安装具有高度可用模式的 Vault。要使用 Helm 图表,请添加 Hashicorp helm 存储库。在安装 Vault 之前,使用上面创建的 serviceaccount 创建一个 Kubernetes secretvault-serviceaccount
。我们将在 Vault 中挂载这个 secret 以访问 serviceaccount 以进行自动解封和 OIDC 身份验证:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault --namespace vault -f values.yaml
在命令中使用以下 values.yaml 文件:
global:
enabled: true
tlsDisable: true
injector:
enabled: false
server:
extraVolumes:
- type: secret
name: vault-serviceaccount
auditStorage:
enabled: true
storageClass: civo-volume
dataStorage:
storageClass: civo-volume
standalone:
enabled: false
ha:
enabled: true
raft:
enabled: true
config: |
ui = true
listener ""tcp"" {
address = "0.0.0.0:8200"
tls_disable = 1
cluster_address = "0.0.0.0:8201"
}
storage ""raft"" {
path = "/vault/data"
retry_join {
leader_api_addr = "http://vault-0.vault-internal:8200"
}
retry_join {
leader_api_addr = "http://vault-1.vault-internal:8200"
}
retry_join {
leader_api_addr = "http://vault-2.vault-internal:8200"
}
autopilot {
cleanup_dead_servers = "true"
last_contact_threshold = "200ms"
last_contact_failure_threshold = "10m"
max_trailing_logs = 250000
min_quorum = 2
server_stabilization_time = "10s"
}
}
seal ""gcpckms"" {
credentials = "/vault/userconfig/vault-serviceaccount/vault-serviceaccount.json"
project = "<GCP-project-id"
region = "global"
key_ring = "vault-auto-unseal-key-ring"
crypto_key = "vault-auto-unseal-key"
}
service_registration "kubernetes" {}
replicas: 3
ui:
enabled: true
在集群上安装 Vault 后,它将创建一个名为vault-ui
的 Kubernetes 服务,其类型为LoadBalancer
,具有公共 IP 地址。现在exec 进入其中一个 pod(vault-0, vault-1, vault-2) 并初始化 Vault 服务器:
vault operator init
这将启动 Vault 服务器并自动解封所有 Vault pod。上述命令的输出很重要。它包含 root_token 和恢复密钥。 将此信息存储在安全的地方。
一旦 Vault 被初始化和解封,我们就可以从我们的本地机器上配置 Vault(而不是在 Pod 中运行 vault 命令)。
设置此环境变量以从本地计算机配置 Vault 集群:
export VAULT_ADDR=http://<public-ip-of-vault-UI-service>:8200
现在,您需要运行:
vault login
从您的本地机器上,它会要求一个令牌。提供我们初始化 Vault 时获得的root_token
(注意 Root 令牌可以访问 Vault 内的所有内容,因此请将其存储在安全的地方)。登录后,您可以运行以下命令来配置 Vault。
1、开启OIDC认证:
保险柜身份验证启用 oidc
- 为您的团队创建保险库策略:
保险库策略写入 sre-policy -<< EOF
# 列出可用的 SSH 角色
路径“ssh-client-signer/roles/*”{
能力 u003d [“创建”、“读取”、“更新”、“删除”、“列表”]
}
# 允许访问 SSH 角色
路径“ssh-client-signer/sign/*”{
能力 u003d [“创建”、“读取”、“更新”、“删除”、“列表”]
}
EOF
- 配置 OIDC 认证:您将需要在先决条件步骤中获得的 client_id、client_secret 和超级管理员电子邮件:
保险库写入 auth/oidc/config -<<EOF
{
"oidc_discovery_url": "https://accounts.google.com",
"oidc_client_id": "<oidc-client-id>",
"oidc_client_secret": "<oidc-client-secret>",
“default_role”:“sre”,
“provider_config”:{
“提供者”:“gsuite”,
“fetch_groups”:真,
"gsuite_service_account": "/path/for/serviceaccount.json",
"gsuite_admin_impersonate": "<SUPER_ADMIN_EMAIL>",
“groups_recurse_max_depth”:5
}
}
EOF
zoz100057`
4. 创建 OIDC 角色:
保险库写入 auth/oidc/role/sre -<<EOF
{
"user_claim":"sub",
"oidc_scopes":"https://www.googleapis.com/auth/admin.directory.group.readonly",
"bound_audiences":"<oidc-client-id>",
"allowed_redirect_uris":"http://VAULT_EXTERNAL_ADDR/ui/vault/auth/oidc/oidc/callback,http://localhost:8250/oidc/callback",
"policies":"civo-sre-policy",
"groups_claim":"群组",
"ttl":"1h",
“bound_claims”:{
“组”:[“sre@domain.com”]
}
}
EOF
`VAULT_EXTERNAL_ADDR`可以是您的保管库服务的域名。
1. 创建 Vault 组和组别名:
vault write identity/group name="sre@domain.com" type="external" \
policies="sre-policy" \
metadata=responsibility="SRE Group"
export GROUP_ID="output-from-the-above-command"
vault auth list -format=json \
| jq -r '."oidc/".accessor' > accessor.txt
vault write identity/group-alias name="sre@domain.com" \
mount_accessor=$(cat accessor.txt) \
canonical_id="$GROUP_ID"
现在您可以测试您的 OIDC 设置。
假设有一个名为[john@domain.com](mailto:john@domain.com)的用户,他们是 GSuite 组[sre@domain.com](mailto:sre@domain.com)的一部分。遵循上述配置后,通过 CLI 进行的 Vault 登录应如下所示:
$ vault login -method=oidc
...
Key Value
token <TOKEN>
token_accessor <TOKEN_ACCESSOR>
token_duration 768h
token_renewable true
token_policies ["default" "reader"]
identity_policies ["sre"]
policies ["default", "sre"]
token_meta_role sre
现在让我们在 Vault 上设置 ssh-secret 引擎。
1. 挂载 Vault SSH 证书密钥引擎并生成 SSH CA 密钥对。这将是我们将在所有远程机器上分发的可信密钥。 **存储从此命令获得的 ssh-publickey,因为它将在以后使用**:
zoz100069`
保险库机密启用 -pathu003dssh-client-signer ssh
保险库写入 ssh-client-signer/config/ca generate_signing_keyu003dtrue
- 创建用于签署客户端 SSH 密钥的 Vault 角色:我们将配置 Vault 角色以根据用户的功能角色签署和颁发具有特定配置的 SSH 证书来签署客户端密钥。您可以创建多个角色并将保管库策略映射到每个角色,但我们将创建一个角色。
allowed_users
:这是此 CA 角色将签署的允许用户列表。如果请求者尝试通过指定不在该角色的 allowed_users 列表中的其他用户来获取密钥签名,它将失败。
ttl
是在签署 SSH 密钥时设置证书到期的地方。在本例中,设置为 30 分钟。证书过期后,用户必须向 Vault 进行身份验证并请求另一个签名的 SSH 证书。
保险库写入 ssh-client-signer/roles/sre -<<EOH
{
“allow_user_certificates”:是的,
"allowed_users": "sre",
"allowed_extensions": "",
“默认扩展”:[
{
“许可证”:“”
}
],
“key_type”:“ca”,
"default_user": "sre",
“ttl”:“30m0s”
}
EOH
远程机器(主机)配置
这些配置应在需要为团队中的其他用户提供 ssh 访问权限的远程计算机 (VM) 上进行。
- 在服务器上创建本地用户。这些是客户端用于通过 SSH 连接到服务器的用户:
sudo useradd -m sre
2.更新受信任的SSH CA公钥:通过导航到/etc/ssh
添加挂载ssh-secret引擎时获得的公钥。如果没有名为trusted-CA.pem 的文件,则创建一个:
回显“公钥”>> 受信任的 CA.pem
- 配置 AuthorizedPrincipalsFile 文件。 AuthorizedPrincipalsFile 配置对于进一步控制接受哪些 SSH 主体进行证书身份验证至关重要。要使客户端身份验证成功,签名 SSH 证书中的主体必须出现在 AuthorizedPrincipalsFile 文件中:
cd /etc/ssh
mkdir auth_principals/
回声`sre`> sre
- 更新 sshd_config 并重启 sshd 服务。
将这些更改添加到/etc/ssh
下的sshd_config
配置文件中:
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
ChallengeResponseAuthentication 否
TrustedUserCAKeys /etc/ssh/trusted-CA.pem
AuthorizedPrincipalsFile 是包含列出接受的主体名称的文件的路径。 %u 表示文件名将是 Linux 用户的用户名。
重启sshd服务
sudo 服务 sshd 重启
客户端配置
现在我们可以尝试 ssh 进入我们之前配置的远程机器。
- 创建 ssh 密钥对。 SSH 公钥将由 Vault SSH CA 签名并返回。然后,此签名的 SSH 证书将用于连接到目标主机(远程机器):
ssh-keygen -b 2048 -t rsa -f ~/.ssh/vault-test
ssh-add ~/.ssh/vault-test
2.登录保险柜
您可以使用 Vault UI 或从命令行使用 Vault 来执行其余步骤。我将使用 Vault 命令行:
保险库登录 -methodu003doidc 角色u003dsre
- 请求 SSH 密钥签名:
祖兹 100093-
保险库写入 -fieldu003dsigned_key ssh-client-signer/sign/sre \
public_keyu003d@$HOME/.ssh/vault-test.pub valid_principalsu003dsre > ~/.ssh/sre-signed-key.pub
记下请求的有效\_principals:`sre`。如果请求不在 Vault SSH CA 角色的 allowed\_users 列表中的任何其他主体,它将失败。这确保了只能签署 SSH 主体的授权列表,从而防止用户请求其他团队使用的其他主体。签名的密钥将存储在`~/.ssh/sre-signed-key.pub`
1. 登录远程机器。上面签名的密钥仅在 30 分钟内有效。您可以通过更改 TTL 来更改此设置,同时为 ssh-signer 创建保险库角色以测试签名密钥是否有效:
祖兹 100097
ssh-keygen -Lf ~/.ssh/sre-signed-key.pub
使用签名证书以sre
用户身份登录远程计算机:
ssh -i ~/.ssh/sre-signed-key.pub sre@<ip-of-remote-machine>
更多推荐
所有评论(0)