【问题标题】:How to generate Signed URL for google cloud storage objects using service-accounts-for-instances如何使用 service-accounts-for-instances 为谷歌云存储对象生成签名 URL
【发布时间】:2019-12-22 19:43:56
【问题描述】:

我正在使用signed-urls 为我的客户提供对谷歌云存储对象的临时访问权限
我有一个服务帐户 json,如下所示:

{
  "type": "service_account",
  "project_id": "my-project",
  "private_key_id": "abcdef1234567890",
  "private_key": "-----BEGIN PRIVATE KEY-----\n<key...>\n-----END PRIVATE KEY-----\n",
  "client_email": "my-app@my-project.iam.gserviceaccount.com",
  "client_id": "1234567890",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/my-app%my-project.iam.gserviceaccount.com"
}

这是我创建签名 url 的方法 - 用 elixir 编写的代码(代码来自 gcs_signer lib)

 def sign_url(private_key, client_email, bucket, object) do
    verb = "GET"
    md5_digest = ""
    content_type = ""
    expires = DateTime.utc_now() |> DateTime.to_unix() |> Kernel.+(1 * 3600)
    resource = "/#{bucket}/#{object}"

    signature = [verb, md5_digest, content_type, expires, resource]
                |> Enum.join("\n") |> generate_signature(private_key)

    url = "https://storage.googleapis.com#{resource}"
    qs = %{
           "GoogleAccessId" => client_email,
           "Expires" => expires,
           "Signature" => signature
         } |> URI.encode_query

    Enum.join([url, "?", qs])
  end

  defp generate_signature(string, private_key) do
    private_key = process_key(private_key)

    string
    |> :public_key.sign(:sha256, private_key)
    |> Base.encode64
  end

  defp process_key(private_key) do
    private_key
    |> :public_key.pem_decode
    |> (fn [x] -> x end).()
    |> :public_key.pem_entry_decode
    |> normalize_private_key
  end

  defp normalize_private_key(private_key) do
    # grab privateKey from the record tuple
    private_key
    |> elem(3)
    |> (fn pk -> :public_key.der_decode(:RSAPrivateKey, pk) end).()
  end

这是我使用 json 文件中的 private_key 创建一个签名的 url

出于安全原因,我们移至 service-accounts-for-instances,而不是使用 json 凭据

我的问题是当我没有 json 凭证时,如何在使用 service-accounts-for-instances 时创建签名的 url?
我唯一拥有的是servie_account_email,它看起来像这样:my-app-gsa@my-project.iam.gserviceaccount.com
我应该使用signBlob api吗?如果是这样,我的 curl 请求会是什么样子?

【问题讨论】:

  • 当您在 Google Compute Engine(任何计算服务)上使用(参考)Google Cloud 凭据(服务帐户)时,您无权访问私钥。这意味着您必须使用 Google Cloud 库或编写自己的代码才能使用 SignBlob(这意味着 Google 正在为您访问私钥)。此链接提供有关 REST API 的信息,然后您可以将其映射到 curl 参数:cloud.google.com/iam/docs/reference/rest/v1/…
  • 要查看 CLI 如何生成 API 调用,请添加命令行选项 --log-http。然后,您可以跟踪由 gcloud 生成的整个预签名 URL。

标签: google-cloud-platform elixir google-cloud-storage


【解决方案1】:

我试图重现您的用例:

  1. 创建两个服务帐号:

    gcloud iam service-accounts create signblob --description signblob
    gcloud iam service-accounts create signforme --description signforme
    # signblob will sign for signforme
    
  2. signblob 服务帐号设置 IAM 角色 (roles/iam.serviceAccountTokenCreator):

    gcloud projects add-iam-policy-binding myproject --member signblob@myproject.iam.gserviceaccount.com --role roles/iam.serviceAccountTokenCreator
    
  3. 使用signblob 服务将 VM 创建为服务帐户:

    gcloud compute instances create instance-10 --zone=us-central1-a --service-account=signblob@myproject.iam.gserviceaccount.com 
    
  4. SSH 到刚刚创建的实例:

    gcloud compute ssh instance-10 --zone=us-central1-a
    
  5. 在实例上创建文件:

    nano file
    cat file
    # This is a file 
    
  6. 使用gcloud 工具为signforme 服务帐户使用--log-http 标志签署文件(blob):

    gcloud iam service-accounts sign-blob --iam-account signblob-source@myproject.iam.gserviceaccount.com file output --log-http
    
  7. 输出:

     signed blob [file] as [output] for [signforme@myproject.iam.gserviceaccount.com] 
    

这是我在之前创建的 VM instance-10 上运行的 curl 命令:

      curl --request POST 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/signblob-source%40myproject.iam.gserviceaccount.com:signBlob?prettyPrint=true&key=[API KEY]' --header 'Authorization: Bearer [ACCESS TOKEN]'  --header 'Accept: application/json'  --header 'Content-Type: application/json' --data '{"payload":"VGhpcyBpcyBhIGZpbGUgCg=="}'   --compressed

ACCESS TOKEN 是gcloud auth application-default print-access-token

输出:

   {"keyId": ,"signedBlob":}

【讨论】:

    【解决方案2】:

    这是我在 elixir 中的代码,它返回以下格式的加密链接: https://storage.googleapis.com/my-bucket/my-file?Expires=1576437298&amp;GoogleAccessId=my-gsa%40project.iam.gserviceaccount.com&amp;Signature=FUgBzvfFCa0YAL
    关注signBlob的google api

    @base_url @https://storage.googleapis.com
    
    def generate_encrypted_url() do
        gcp_service_account = "my-gsa@project.iam.gserviceaccount.com"
        bucket = "my-bucket", 
        object ="my-file"
        get_signed_url(gcp_service_account, bucket, object)
    end
    
    
    
      def get_signed_url(gcp_service_account, bucket, object) do
        %Tesla.Client{pre: [{Tesla.Middleware.Headers, :call, [auth_headers]}]} = get_connection()
        headers = [{"Content-Type", "application/json"}] ++ auth_headers
        url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/#{gcp_service_account}:signBlob"
        expires = DateTime.utc_now() |> DateTime.to_unix() |> Kernel.+(1 * 3600)
        resource = "/#{bucket}/#{object}"
        signature = ["GET", "", "", expires, resource] |> Enum.join("\n") |> Base.encode64()
        body = %{"payload" => signature} |> Poison.encode!()
        {:ok, %{status_code: 200, body: result}} = HTTPoison.post(url, body, headers)
    
        %{"signedBlob" => signed_blob} = Poison.decode!(result)
        qs = %{
               "GoogleAccessId" => gcp_service_account,
               "Expires" => expires,
               "Signature" => signed_blob
             } |> URI.encode_query
        Enum.join(["#{@base_url}#{resource}", "?", qs])
      end
    
      def get_connection() do
        {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
        GoogleApi.Storage.V1.Connection.new(token.token)
      end
    

    【讨论】:

      猜你喜欢
      • 2013-12-27
      • 1970-01-01
      • 2018-05-15
      • 2014-10-23
      • 2019-03-16
      • 2018-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多