<h1>Context</h1>

<p>I have a bash script that uses the <a href="https://cloud.google.com/sdk/gcloud/" rel="nofollow noreferrer"><code>gcloud</code></a> command-line tool to perform maintenance operations.</p>

<p>This script works fine.</p>

<p>This script is in a docker image based on <a href="https://hub.docker.com/r/google/cloud-sdk" rel="nofollow noreferrer"><code>google/cloud-sdk</code></a>, executed automatically directly through the container entrypoint.</p>

<p>The goal is to have it executed periodically through a <a href="https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/" rel="nofollow noreferrer">Kubernetes CronJob</a>. This works too.</p>

<p>I have currently not setup anything regarding authentication, so my script uses the <a href="https://cloud.google.com/compute/docs/access/service-accounts?hl=en_US#the_default_service_account" rel="nofollow noreferrer">Compute Engine default service account</a>.</p>

<p>So far so good, however, I need to stop using this default service account, and switch to a separate service account, with an API key file. That's where  the problems start.</p>

<h1>Problem</h1>

<p>My plan was to mount my API key in the container through a Kubernetes Secret, and then use the <code>GOOGLE_APPLICATION_CREDENTIALS</code> (documented <a href="https://cloud.google.com/docs/authentication/production" rel="nofollow noreferrer">here</a>) to have it loaded automatically, with the following (simplified) configuration :</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: some-name
spec:
  schedule: "0 1 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: some-name
              image: some-image-path
              imagePullPolicy: Always
              env:
                - name: GOOGLE_APPLICATION_CREDENTIALS
                  value: "/credentials/credentials.json"
              volumeMounts:
                - name: credentials
                  mountPath: /credentials
          volumes:
            - name: credentials
              secret:
                secretName: some-secret-name
</code></pre>

<p>But apparently, the <code>gcloud</code> tool behaves differently from the programming-languages SDKs, and ignores this env variable completely.</p>

<p>The <a href="https://hub.docker.com/r/google/cloud-sdk" rel="nofollow noreferrer">image documentation</a> isn't much help either, since it only gives you a way to change the gcloud config location.</p>

<p>Moreover, I'm pretty sure that I'm going to need a way to provide some extra configuration to gcloud down the road (project, zone, etc…), so I guess my solution should give me the option to do so from the start.</p>

<h1>Possible solutions</h1>

<p>I've found a few ways to work around the issue :</p>

<ul>
<li><p>Change the entrypoint script of my image, to read environment variables, and execute env preparation with <code>gcloud</code> commands :</p>

<p>That's the simplest solution, and the one that would allow me to keep my Kubernetes configuration the cleanest (each environment only differs by some environment variables). It requires however maintaining my own copy of the image I'm using, which I'd like to avoid if possible.</p></li>
<li><p>Override the entrypoint of my image with a Kubernetes configMap mounted as a file :</p>

<p>This option is probably the most convenient : execute a separate configmap for each environment, where I can do whatever environment setup I want (such as <code>gcloud auth activate-service-account --key-file /credentials/credentials.json</code>). Still, it feels hacky, and is hardly readable compared to env variables.</p></li>
<li><p>Manually provide configuration files for <code>gcloud</code> (in <code>/root/.config/gcloud</code>) :</p>

<p>I suppose this would be the cleanest solution, however, the configuration syntax doesn't seem really clear, and I'm not sure how easy it would be to provide this configuration through a configMap.</p></li>
</ul>

<p>As you can see, I found ways to work around my issue, but none of them satisfies me completely. Did I miss something ?</p>

<p>For the record, here is the solution I finally used, although it's still a workaround in my opinion :</p>

<pre><code>apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: some-name
spec:
  schedule: "0 1 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: some-name
              image: some-image-path
              imagePullPolicy: Always
              command: ["/bin/bash", "/k8s-entrypoint/entrypoint.sh"]
              volumeMounts:
                - name: credentials
                  mountPath: /credentials
                - name: entrypoint
                  mountPath: /k8s-entrypoint
          volumes:
            - name: credentials
              secret:
                secretName: some-secret-name
            - name: entrypoint
              configMap:
                name: entrypoint

</code></pre>

<p>With the following ConfigMap :</p>

<pre><code>apiVersion: v1
kind: ConfigMap
metadata:
  name: entrypoint
data:
  entrypoint.sh: |
    #!/bin/bash

    gcloud auth activate-service-account --key-file /credentials/credentials.json

    # Chainload the original entrypoint
    exec sh -c /path/to/original/entrypoint.sh
</code></pre>
