将Google服务帐户凭据传递给Docker

时间:2017-09-28 03:34:39

标签: docker google-cloud-platform google-cloud-storage google-compute-engine google-cloud-sdk

我的用例与其他有这个问题的用例略有不同,所以前面有一点描述:

我正在开发Google Cloud并且已经进行了#24; dockerized" Django app。部分应用程序依赖于使用gsutil将文件移入/移出Google存储桶。出于各种原因,我们不希望使用Google Container Engine来管理我们的容器。相反,我们希望通过启动其他Google Compute VM来水平扩展,这将反过来运行此Docker容器。与https://cloud.google.com/python/tutorials/bookshelf-on-compute-engine类似,但我们将使用容器而不是拉动git存储库。

VM将基于Debian基本映像构建,依赖项的启动和安装(例如Docker本身)将使用启动脚本(例如gcloud compute instances create some-instance --metadata-from-file startup-script=/path/to/startup.sh)进行编排。

如果我手动创建VM,请使用sudo -s进行提升,运行gsutil config -f(在/root/.boto创建凭据文件),然后运行我的docker容器(请参阅下面的Dockerfile)< / p>

docker run -v /root/.boto:/root/.boto username/gs gsutil ls gs://my-test-bucket

然后它的工作原理。但是,这需要我的交互来创建boto文件。

我的问题是:如何将默认服务凭据传递给将在该新VM中启动的Docker容器?

gsutil开箱即用,即使是新鲜的&#34; Debian VM,因为它使用所有VM加载的默认计算引擎凭据。有没有办法使用这些凭据并将它们传递给docker容器?在新VM上第一次调用gsutil后,我注意到它创建了〜/ .gsutil和〜/ .config文件夹。不幸的是,在Docker中安装了这两个

docker run -v ~/.config/:/root/.config -v ~/.gsutil:/root/.gsutil username/gs gsutil ls gs://my-test-bucket

无法解决我的问题。它告诉我:

ServiceException: 401 Anonymous users does not have storage.objects.list access to bucket my-test-bucket.

最小的gsutil Dockerfile(不是我的):

FROM alpine
#install deps and install gsutil
RUN apk add --update \
    python \
    py-pip \
    py-cffi \
    py-cryptography \
  && pip install --upgrade pip \
  && apk add --virtual build-deps \
    gcc \
    libffi-dev \
    python-dev \
    linux-headers \
    musl-dev \
    openssl-dev \
  && pip install gsutil \
  && apk del build-deps \
  && rm -rf /var/cache/apk/*
CMD ["gsutil"]

添加:解决方法:

我已经解决了我的问题,但它非常迂回,所以如果可能的话,仍然对更简单的方式感兴趣。所有细节如下:

首先,描述: 我首先在Web控制台中创建了一个服务帐户。然后,我将JSON密钥文件(称为credentials.json)保存到存储桶中。在GCE VM的启动脚本中,我将该密钥文件复制到本地文件系统(gsutil cp gs://<bucket>/credentials.json /gs_credentials/)。然后我启动我的docker容器,挂载该本地目录。然后,当docker容器启动时,它会运行一个脚本来验证credentials.json(在docker中创建一个.boto文件),导出BOTO_PATH =,最后我可以在Docker容器中执行gsutil操作。

以下是一个小工作示例的文件:

Dockerfile:

FROM alpine
#install deps and install gsutil
RUN apk add --update \
    python \
    py-pip \
    py-cffi \
    py-cryptography \
    bash \
    curl \
  && pip install --upgrade pip \
  && apk add --virtual build-deps \
    gcc \
    libffi-dev \
    python-dev \
    linux-headers \
    musl-dev \
    openssl-dev \
  && pip install gsutil \
  && apk del build-deps \
  && rm -rf /var/cache/apk/*

# install the gcloud SDK- 
# this allows us to use gcloud auth inside the container
RUN curl -sSL https://sdk.cloud.google.com > /tmp/gcl \
      && bash /tmp/gcl --install-dir=~/gcloud --disable-prompts

RUN mkdir /startup
ADD gsutil_docker_startup.sh /startup/gsutil_docker_startup.sh
ADD get_account_name.py /startup/get_account_name.py

ENTRYPOINT ["/startup/gsutil_docker_startup.sh"]

gsutil_docker_startup.sh:采用单个参数,这是JSON格式服务帐户凭据文件的路径。该文件存在,因为主机上的目录已安装在容器中。

#!/bin/bash

CRED_FILE_PATH=$1

mkdir /results

# List the bucket, see that it gives a "ServiceException:401"
gsutil ls gs://<input bucket> > /results/before.txt

# authenticate the credentials- this creates a .boto file:
/root/gcloud/google-cloud-sdk/bin/gcloud auth activate-service-account --key-file=$CRED_FILE_PATH

# need to extract the service account which is like:
# <service acct ID>@<google project>.iam.gserviceaccount.com"
SERVICE_ACCOUNT=$(python /startup/get_account_name.py $CRED_FILE_PATH)

# with that service account, we can locate the .boto file:
export BOTO_PATH=/root/.config/gcloud/legacy_credentials/$SERVICE_ACCOUNT/.boto

# List the bucket and copy the file to an output bucket for good measure
gsutil ls gs://<input bucket> > /results/after.txt
gsutil cp /results/*.txt gs://<output bucket>/

get_account_name.py:

import json
import sys
j = json.load(open(sys.argv[1]))
sys.stdout.write(j['client_email'])

然后,GCE启动脚本(在VM启动时自动执行)是:

#!/bin/bash

# <SNIP>
# Install docker, other dependencies
# </SNIP>

# pull docker image
docker pull userName/containerName

# get credential file:
mkdir /cloud_credentials
gsutil cp gs://<bucket>/credentials.json /cloud_credentials/creds.json

# run container
# mount the host machine directory where the credentials were saved.
# Note that the container expects a single arg, 
# which is the path to the credential file IN THE CONTAINER
docker run -v /cloud_credentials:/cloud_credentials \ 
    userName/containerName /cloud_credentials/creds.json

1 个答案:

答案 0 :(得分:1)

您可以为实例分配Specific Service Account,然后在代码中使用应用程序默认凭据。请在测试之前验证这些点。

  • 将实例访问范围设置为:“允许对所有Cloud API的完全访问权限”,因为它们not really a security feature
  • 为您的服务帐户设置正确的角色:“存储对象查看器”

身份验证令牌通过retrieved automatically by Application Default Credential通过Google Metadata Server,您的实例和Docker容器也可以使用。 无需管理任何凭据。

def implicit():
  from google.cloud import storage

  # If you don't specify credentials when constructing the client, the
  # client library will look for credentials in the environment.
  storage_client = storage.Client()

  # Make an authenticated API request
  buckets = list(storage_client.list_buckets())
  print(buckets)

我也很快地在docker上进行了测试,并且表现出色

yann@test:~$ gsutil cat gs://my-test-bucket/hw.txt
Hello World
yann@test:~$ docker run --rm google/cloud-sdk gsutil cat gs://my-test-bucket/hw.txt
Hello World