停止下载Google Cloud Service帐户密钥!

TL;DR: Generating and distributing service account keys poses severe security risks to your organization. They are long-lived credentials that are not automatically rotated. These keys can be leaked accidentally or maliciously allowing attackers to gain access to your sensitive GCP resources. Additionally, when used actions cannot be attributable back to a human. You don’t actually have to download these long-lived keys. There’s a better way!

TL; DR:生成和分发服务帐户密钥会对组织造成严重的安全风险。 它们是长期存在的凭证,不会自动轮换。 这些密钥可能会意外或恶意泄露,从而使攻击者可以访问您的敏感GCP资源。 另外,当使用的动作不能归因于人类时。 您实际上不必下载这些长期存在的密钥。 有更好的方法!

服务帐户,OAuth2和您 (Service Accounts, OAuth2 and You)

For some background, almost every change you want to make in Google Cloud from creating a GKE cluster to reading from a GCS bucket is handled using an API. This API is authenticated using the OAuth2 protocol, which basically means there’s a short lived (1 hour default) access token attached to every authenticated request. If you’re familiar with the whole “Sign in with Google” popup, that’s OAuth2 hard at work authenticating you with your Google credentials. Once you’re authenticated, an access token is attached to all your API requests whether you’re using gcloud, terraform, SDKs, or the console. In Google Cloud, we use a lot of automation and web services which similarly need those tokens, but robots aren’t very good at opening browsers and typing in passwords so they need some sort of verifiable identity. Enter Service Accounts.

在某些背景下,几乎您要在Google Cloud中进行的所有更改(从创建GKE群集到从GCS存储桶读取)都使用API​​进行处理。 此API使用OAuth2协议进行身份验证,这基本上意味着每个经过身份验证的请求都附有短暂的访问令牌(默认为1小时)。 如果您熟悉整个“使用Google登录”弹出窗口,则OAuth2会很努力地使用Google凭据对您进行身份验证。 通过身份验证后,无论您使用的是gcloudterraform ,SDK还是控制台,访问令牌都会附加到所有API请求中。 在Google Cloud中,我们使用了很多自动化和Web服务,它们同样需要这些令牌,但是机器人并不是很擅长打开浏览器并输入密码,因此它们需要某种可验证的身份。 输入服务帐户

Service accounts allow automated users to prove their identity using a public/private key pair in the form of a JSON file. A service account also has the same ability as users or groups to bind to IAM roles to do things in GCP. To make an API request, a service account will sign a JWT token with its private key and the Google authentication system will verify that signature with the public key, granting an access token. This basic (and oversimplified) concept is important for later parts of this post. If you’d like to read more about this flow, check out RFC 7523.

服务帐户允许自动化用户使用JSON文件形式的公用/专用密钥对来证明其身份。 服务帐户还具有与用户或组绑定到IAM角色以在GCP中执行操作的功能。 要发出API请求,服务帐户将使用其私钥对JWT令牌进行签名,Google身份验证系统将使用公钥来验证该签名,并授予访问令牌。 这个基本(且过于简化)的概念对于本文的后续部分很重要。 如果您想了解有关此流程的更多信息,请参阅RFC 7523

You should never need to generate and download a service account key to use a service account within Google Cloud infrastructure.

您无需生成和下载服务帐户密钥即可在Google Cloud基础架构中使用服务帐户。

Service accounts are very easy to use within Google Cloud. Most, if not all, compute resources (i.e. GCE instances, GKE Pods, Cloud Functions, etc.) support the ability to attach a service account. This allows these resources to act as the service account, call Google SDKs and APIs within the bounds of permissions granted to the service account. You should never need to generate and download a service account key to use a service account within Google Cloud infrastructure. A risk emerges when developers think they need a service account to accomplish a task, so they generate and download a key.

服务帐户在Google Cloud中非常易于使用。 大多数(如果不是全部)计算资源(例如,GCE实例,GKE Pod,Cloud Functions等)都支持附加服务帐户的功能。 这样一来,这些资源就可以充当服务帐户,并在授予该服务帐户的权限范围内调用Google SDK和API。 您无需生成和下载服务帐户密钥即可在Google Cloud基础架构中使用服务帐户。 当开发人员认为他们需要服务帐户来完成任务时,就会产生风险,因此他们生成并下载密钥。

I cannot tell you how often I see documentation or tutorials instruct folks to download these service account keys and use them indefinitely or worse, store them in their source code working directory. Doing this, you’re literally one line in a .gitignore from committing this highly sensitive secret to Github and getting breached.

我无法告诉您我经常看到文档或教程指示人们下载这些服务帐户密钥并无限期或更糟地使用它们,并将它们存储在其源代码工作目录中。 这样做,实际上是将.gitignore提交给Github并遭到破坏的行。

短暂的代币FTW! (Short lived tokens FTW!)

Remember how I said that if you have the Service Account’s private key, you can sign a JWT token and be granted an API access token? Well there is a way to do that without ever needing to download the key.

还记得我怎么说的话:如果您拥有服务帐户的私钥,那么您可以签名JWT令牌并被授予API访问令牌? 好吧,有一种方法可以做到,而无需下载密钥。

Let’s say I have a service account that is used for GKE so it has the role roles/container.developer. We’ll call this service account k8s@project.iam.gserviceaccount.com. Let’s further say that my user ryan@example.com isn’t allowed to download the key to this service account and doesn’t have direct permissions to mess with GKE but what I do have is the magic role roles/iam.serviceAccountTokenCreator. Now all I have to do to setup my GKE credentials with the gcloud command is:

假设我有一个用于GKE的服务帐户,因此它具有角色roles/container.developer 。 我们将此服务帐户k8s@project.iam.gserviceaccount.com 。 再说ryan@example.com ,我的用户ryan@example.com不允许将密钥下载到该服务帐户,并且没有直接权限与GKE混淆,但是我所拥有的只是魔术角色roles/iam.serviceAccountTokenCreator 。 现在,使用gcloud命令设置我的GKE凭据所需要做的就是:

gcloud 

This is great because it allows this command to use a service account without actually having the key! Not only that but you always know you are impersonating because a warning message pops up letting you know.

这很棒,因为它允许该命令使用服务帐户而不实际拥有密钥! 不仅如此,而且您始终知道自己在冒充别人,因为会弹出警告消息让您知道。

WARNING: This command is using service account impersonation. All API calls will be executed as [

But if you’re running multiple commands with the same service account, this can be annoying to type over and over. Instead, let’s set this with gcloud config.

但是,如果您使用同一个服务帐户运行多个命令,那么一遍又一遍地输入可能会很烦人。 相反,让我们使用gcloud config设置。

gcloud config set auth/impersonate_service_account \

gcloud container clusters get-credentials my-cluster
# Other gcloud commands :)

This is much better! Now we can impersonate a user for multiple commands without having to constantly add that --impersonate-service-account flag. But what if, like me, you constantly switch back and forth between service accounts for different projects. We can write a very simple bash script to simplify typing and remembering service accounts that you use frequently.

这样好多了! 现在,我们可以模拟用户执行多个命令,而不必不断添加--impersonate-service-account标志。 但是,如果像我一样,您不断在不同项目的服务帐户之间来回切换,该怎么办? 我们可以编写一个非常简单的bash脚本,以简化键入和记住您经常使用的服务帐户。

#!/bin/bashIMPERSONATE='gcloud config set auth/impersonate_service_account'impersonate() {
sa=$1
echo "Impersonating $sa"
$IMPERSONATE $sa
}case $1 in
gke)
impersonate k8s@project.iam.gserviceaccount.com
;;
admin)
impersonate admin@other-project.iam.gserviceaccount.com
;;
clear)
gcloud config unset auth/impersonate_service_account
;;
*)
echo "Usage: Updates impersonated service account"
echo " gsa [gke|admin|clear]"
esac

Now you could execute this with the following before using gcloud:

现在,您可以在使用gcloud之前使用以下命令执行此gcloud

$ gsa gke
Impersonating k8s@project.iam.gserviceaccount.com
Updated property [auth/impersonate_service_account].
$ gsa clear
Unset property [auth/impersonate_service_account].

You could make this more robust by reading from a config file if you like, but I think a single-file script gets the point across. Now for every new service account you want to use, simply add it and a short name for it to this script and you’re off.

如果愿意,您可以通过读取配置文件来增强此功能,但我认为单文件脚本可以解决这一问题。 现在,对于您要使用的每个新服务帐户,只需将其和它的简称添加到此脚本中就可以了。

那Terraform呢? (What about Terraform?)

We’ve spent all this time talking about a better way to consume service accounts through gcloud but what about the very common use case of Terraform? For development purposes, we need to test our infrastructure as code somehow. Thankfully, the google terraform provider supports directly passing an OAuth2 token as an environment variable. All you have to do to get this token and tell Terraform about it is this:

我们一直在讨论通过gcloud消费服务帐户的更好方法,但是Terraform的非常常见的用例又如何呢? 出于开发目的,我们需要以某种方式对基础结构进行测试。 值得庆幸的是, Google terraform提供程序支持直接将OAuth2令牌作为环境变量传递。 获得此令牌并将其告知Terraform所要做的就是:

export GOOGLE_OAUTH_ACCESS_TOKEN=$(gcloud auth print-access-token)
terraform apply

You could further simplify this by wrapping it in a Makefile, but regardless, now you have a token that will only live in your environment for 1 hour and be useless to an attacker after that!

您可以通过将其包装在Makefile中来进一步简化此操作,但是无论如何,现在您有了一个令牌,该令牌只能在您的环境中使用1个小时,之后对攻击者无用!

归因和记录 (Attribution and Logging)

The SecOps folks may be thinking, how do I attribute and audit actions taken by a user impersonating a service account? In Cloud Logging, every API call executed by a service account that has been impersonated has the following structure within it:

SecOps人士可能会思考,我该如何归因和审核模拟服务帐户的用户所采取的措施? 在Cloud Logging中,已被模拟的服务帐户执行的每个API调用均具有以下结构:

{
"principalEmail": "k8s@project.iam.gserviceaccount.com",
"serviceAccountDelegationInfo": [
{
"firstPartyPrincipal": {
"principalEmail": "ryan@example.com"
}
}
]
}

You can also get a higher level of detail if you enable Data Access logs. The below Cloud Logging filter will include every API call that ryan@example.com made while impersonating. I’m sure you can find other clever filters as well.

如果启用了数据访问日志,则还可以获得更高级别的详细信息。 下面的Cloud Logging过滤器将包含ryan@example.com在模拟时进行的每个API调用。 我相信您也可以找到其他聪明的过滤器。

protoPayload.authenticationInfo.serviceAccountDelegationInfo.0.firstPartyPrincipal.principalEmail="ryan@example.com"

I’ll also point out that this level of attribution is impossible if you allow users to download service account keys since they are effectively using shared credentials, assuming more than one person has access to download the same key. To illustrate, this is the only info you get in the logs if I could download the k8s service account key and used it.

我还要指出, 如果您允许用户下载服务帐户密钥 ,则这种归属级别是不可能的,因为他们假设有多个人可以下载同一密钥,因此他们实际上是在使用共享凭据。 为了说明这一点,如果我可以下载k8s服务帐户密钥并使用它,那么这是您在日志中获得的唯一信息。

authenticationInfo: {
principalEmail: "k8s@project.iam.gserviceaccount.com"
serviceAccountKeyName: "//iam.googleapis.com/projects/project/serviceAccounts/k8s@project.iam.gserviceaccount.com/keys/caed69e352ae12ab17e1962de5bac31062495876"
}

If I’m a forensic analyst or an auditor, there’s no way I could figure out definitively what human executed this API request unless each user has their own service account or key and that’s defined somewhere. Even still, that is very difficult to trace back.

如果我是法医分析师或审计师,除非每个用户都有自己的服务帐户或密钥,并且在某个地方定义,否则我无法确切确定执行此API请求的人员。 即使如此,这也很难追溯。

注意事项 (Caveats)

There are some use cases where downloading a service account key to your workstation is necessary, but they are not the norm. Keeping secrets like this short-lived locally should be the goal, the same way we should enable MFA and not use hunter2 as our password. For the obvious cases where service account keys must be downloaded to use GCP resources from your datacenter or another cloud, I’d recommend taking a look at HashiCorp Vault which has a plugin to checkout short-lived service account keys.

在某些用例中,有必要将服务帐户密钥下载到您的工作站,但这不是正常的情况。 我们的目标是在本地这样短暂的机密,这与启用MFA而不是使用hunter2作为我们的密码的方式相同。 对于明显的情况,必须下载服务帐户密钥才能使用数据中心或其他云中的GCP资源,我建议您看一下HashiCorp Vault ,它具有一个可签出短期服务帐户密钥的插件。

So now that you know, please stop downloading service account keys! :)

因此,既然您知道了,请停止下载服务帐户密钥! :)

下一步 (Next Steps)

翻译自: https://medium.com/@jryancanty/stop-downloading-google-cloud-service-account-keys-1811d44a97d9

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值