如何从.NET Core应用程序使用JWT身份验证调用GCP第二代云函数。

huangapple go评论67阅读模式
英文:

How to invoke gcp gen 2 cloud function from dotne core application with jwt authentication

问题

如何为account2创建JWT令牌?

英文:

I have created 2nd generation cloud function in gcp and deafult service account is attached to it.For security concern I have created another service account account2 and give appropriate permissions to it like function invoker.
But for calling this function from dotnet core we have to pass jwt token, How to create jwt token for account2?

答案1

得分: 1

我不太清楚为什么您需要额外的服务账户来调用您的函数(例如,您可以在您的云函数上使用此帐户2作为运行时服务账户...)

最清晰和最安全的解决方案是使用服务账户冒充。原则如下:您授权当前运行时服务账户(帐户1)冒充(代表)服务账户2创建令牌。

由于您将通过冒充使用服务账户2的权限,因此您将能够调用您的函数。

为了实现这一点,您的运行时服务账户必须在帐户2(或更广泛地在项目上,但最好缩小角色的范围)上具有"Service Account Token Creator"角色。然后,您可以使用这段Python代码

import google.oauth2.id_token
import google.auth.transport.requests
from google.auth.impersonated_credentials import IDTokenCredentials
SCOPES = ['https://www.googleapis.com/auth/cloud-platform']

request = google.auth.transport.requests.Request()

audience = 'my_cloud_function_url'

creds, _ = google.auth.default(scopes=SCOPES)

icreds = google.auth.impersonated_credentials.Credentials(
        source_credentials=creds,
        target_principal="<Service account2>",
        target_scopes=SCOPES)

id = IDTokenCredentials(icreds, target_audience=audience,include_email=True)
print(id.token)
#example of raw idToken

from google.auth.transport.requests import AuthorizedSession
authed_session = AuthorizedSession(icreds)
request = google.auth.transport.requests.Request(session=authed_session)

# Use your request to post, get, put....

注意:您可以使用服务账户密钥文件找到解决方案,但这是不好的做法,正如文档中在这里的注释中提到的。

英文:

I don't really know why you need an additional service account to invoke your functions (you could use this account2 as runtime service account on your Cloud Functions for instance...)

The cleanest and safest solution is to use service account impersonation. The principle is the following: you autorise the current runtime service account (account1) to impersonate (to create a token on behalf of) the service account2

Because you will use the permission of the service account 2 by impersonation, you will be able to invoke your function.

To achieve that, your runtime service account must have the role "Service Account Token Creator" on the account2 (or more widely on the project, but it's better to narrow the scope of the role). Then, you can use this Python code

import google.oauth2.id_token
import google.auth.transport.requests
from google.auth.impersonated_credentials import IDTokenCredentials
SCOPES = [&#39;https://www.googleapis.com/auth/cloud-platform&#39;]

request = google.auth.transport.requests.Request()

audience = &#39;my_cloud_function_url&#39;

creds, _ = google.auth.default(scopes=SCOPES)

icreds = google.auth.impersonated_credentials.Credentials(
        source_credentials=creds,
        target_principal=&quot;&lt;Service account2&gt;&quot;,
        target_scopes=SCOPES)

id = IDTokenCredentials(icreds, target_audience=audience,include_email=True)
print(id.token)
#example of raw idToken

from google.auth.transport.requests import AuthorizedSession
authed_session = AuthorizedSession(icreds)
request = google.auth.transport.requests.Request(session=authed_session)

# Use your request to post, get, put....

Note: You can find solution with service account key file, and it's a bad practice, as mentioned in the documentation here in the note

答案2

得分: 0

在博客***“如何从Google云服务帐户密钥创建JWT令牌”中,由Rajathithan Rajasekar撰写,详细解释了如何使用python创建JWT令牌*。按照博客中提到的步骤来创建JWT令牌并在你的.Net应用程序中使用它。

  • 在你的本地系统或服务器上创建一个项目目录
  • 创建一个 .py 文件来编写你的python脚本
  • 打开你的python脚本并编写导入所有所需软件包的import语句
  • 定义所有所需的变量,如服务帐户凭证路径、密钥文件路径、服务帐户电子邮件地址、受众和到期时间长度(TTL)
  • 传递所需的值,如到期时间、发行者、受众和电子邮件地址等。
  • 发送签名负载并检索JWT令牌

以下代码在上述博客中提供,将返回已签名的JWT令牌,你可以在你的.Net应用程序中使用它来执行所需的功能。

> from google.auth import crypt
> from google.auth import jwt
> import os
> import io
> import json
> import time
>
> # 服务帐户密钥路径
> credential_path = "service-account-key.json"
> os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credential_path
>
> sa_keyfile = credential_path
>
> # 获取服务帐户电子邮件并从服务帐户密钥文件中加载json数据。
> with io.open(credential_path, "r", encoding="utf-8") as json_file:
> data = json.loads(json_file.read())
> sa_email = data['client_email']
>
> audience = "https://yourcloudendpoint"
> # 例如: "https://pubsub.googleapis.com/google.pubsub.v1.Publisher"
> # 如果你在API中使用云端终结点,可以使用安全定义中的x-google-audiences值。
>
> # JWT令牌的到期时间
> expiry_length = 1000
>
>
> def generate_jwt(sa_keyfile,
> sa_email,
> audience,
> expiry_length=1000):
> """生成使用Google API服务帐户签名的JSON Web Token。"""
>
> now = int(time.time())
>
> # 构建负载
> payload = {
> 'iat': now,
> # 在'expiry_length'秒后过期。
> "exp": now + expiry_length,
> # iss必须与swagger规范中的安全配置中的'issuer'匹配(例如服务帐户电子邮件)。它可以是任何字符串。
> 'iss': sa_email,
> # aud必须是你的终结点服务名称,或与OpenAPI文档中指定的'x-google-audience'的值匹配。
> 'aud': audience,
> # sub和email应与服务帐户的电子邮件地址匹配
> 'sub': sa_email,
> 'email': sa_email
> }
>
> # 使用密钥文件签名
> signer = crypt.RSASigner.from_service_account_file(sa_keyfile)
> jwt_token = jwt.encode(signer, payload)
> # print(jwt_token.decode('utf-8'))
> return jwt_token
>
>
> signed_jwt = generate_jwt(sa_keyfile, sa_email, audience)
> print(signed_jwt)

注意: 代码和内容取自提及的博客。

更新:

正如 @guillaumeblaquiere 所说,使用密钥文件确实是一种不好的做法,但如果你的实现需要使用它们,你可以对它们进行加密,或者使用一个密钥管理器而不是拥有本地副本你的密钥文件。需要采取其他措施,比如每隔一段时间旋转密钥。我之所以建议这样做是因为你询问了使用JWT令牌。我忘了在解决方案中添加这一点。

英文:

In the blog “How to create a JWT token from Google Cloud Service Account Key” written by Rajathithan Rajasekar, there is a detailed explanation on creating a JWT token using python. Follow the below steps mentioned in the blog for creating the JWT token and use it in your .Net application.

  • Create a project directory in your local system or server
  • Create a .py file for writing your python script
  • Open your python script and write the import statements for all the
    required packages
  • Define all the required variables like service account cred path, keyfile
    path, service-account email address, audience and expiry_length (TTL)
  • Pass the required values like expiry, issuer, audience and email address
    etc.
  • Send the signed payload and retrieve the JWT token

The below code which is given in the above blog will return the signed JWT token you can use in your .Net application for performing required functions.

> from google.auth import crypt
> from google.auth import jwt
> import os
> import io
> import json
> import time
>
> # Service account key path
> credential_path = "service-account-key.json"
> os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credential_path
>
> sa_keyfile = credential_path
>
> # Get service account email and load the json data from the service account key file.
> with io.open(credential_path, "r", encoding="utf-8") as json_file:
> data = json.loads(json_file.read())
> sa_email = data['client_email']
>
> audience = "https://yourcloudendpoint"
> # e.g : "https://pubsub.googleapis.com/google.pubsub.v1.Publisher"
> # If you use cloud endpoints for you API, you can take the x-google-audiences value in your security definitions.
>
> # Expiry time for your JWT token
> expiry_length = 1000
>
>
> def generate_jwt(sa_keyfile,
> sa_email,
> audience,
> expiry_length=1000):
> """Generates a signed JSON Web Token using a Google API Service Account."""
>
> now = int(time.time())
>
> # build payload
> payload = {
> 'iat': now,
> # expires after 'expiry_length' seconds.
> "exp": now + expiry_length,
> # iss must match 'issuer' in the security configuration in your
> # swagger spec (e.g. service account email). It can be any string.
> 'iss': sa_email,
> # aud must be either your Endpoints service name, or match the value
> # specified as the 'x-google-audience' in the OpenAPI document.
> 'aud': audience,
> # sub and email should match the service account's email address
> 'sub': sa_email,
> 'email': sa_email
> }
>
> # sign with keyfile
> signer = crypt.RSASigner.from_service_account_file(sa_keyfile)
> jwt_token = jwt.encode(signer, payload)
> # print(jwt_token.decode('utf-8'))
> return jwt_token
>
>
> signed_jwt = generate_jwt(sa_keyfile, sa_email, audience)
> print(signed_jwt)

Note: The code and the content is taken from the blog which is mentioned in the post.

Update:

As @guillaumeblaquiere said it's indeed a bad practice to use the keyfiles but if your implementation requires you to use them, you can encrypt them or use a keymanager instead of having a localized copies of your keyfile. Additional measures needs to be taken like rotating the keys for every period of time. I have suggested this because you have asked about using the JWT token. I forgot to add this point in the solution.

huangapple
  • 本文由 发表于 2023年6月9日 11:33:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437041.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定