Add GCE auth support for GKE-based Kubernetes

Change-Id: I757b6fd0111945373615f4c509db21bba33f3a02
diff --git a/_modules/helm.py b/_modules/helm.py
index a71c53c..6493aa5 100644
--- a/_modules/helm.py
+++ b/_modules/helm.py
@@ -23,6 +23,9 @@
     env = {'HELM_HOME': HELM_HOME}
     if tiller_kwargs['kube_config']:
         env['KUBECONFIG'] = tiller_kwargs['kube_config']
+    if tiller_kwargs['gce_service_token']:
+        env['GOOGLE_APPLICATION_CREDENTIALS'] = \
+            tiller_kwargs['gce_service_token']
     return {
         'cmd': ('helm',) + tiller_args + args,
         'env': env,
@@ -31,21 +34,23 @@
 
 def release_exists(name, namespace='default',
                    tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None):
+                   kube_config=None, gce_service_token=None):
     cmd = _helm_cmd('list', '--short', '--all', '--namespace', namespace, name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
-                    kube_config=kube_config)
+                    kube_config=kube_config,
+                    gce_service_token=gce_service_token)
     return __salt__['cmd.run_stdout'](**cmd) == name
 
 
 def release_create(name, chart_name, namespace='default',
                    version=None, values=None,
                    tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None):
+                   kube_config=None, gce_service_token=None):
     tiller_args = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
+        'gce_service_token': gce_service_token,
     }
     args = []
     if version is not None:
@@ -61,21 +66,23 @@
 
 
 def release_delete(name, tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None):
+                   kube_config=None, gce_service_token=None):
     cmd = _helm_cmd('delete', '--purge', name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
-                    kube_config=kube_config)
+                    kube_config=kube_config,
+                    gce_service_token=gce_service_token)
     return ok_or_output(cmd, 'Failed to delete release "{}"'.format(name))
 
 
 def release_upgrade(name, chart_name, namespace='default',
                     version=None, values=None,
                     tiller_namespace='kube-system', tiller_host=None,
-                    kube_config=None):
+                    kube_config=None, gce_service_token=None):
     tiller_args = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
+        'gce_service_token': gce_service_token,
     }
     args = []
     if version is not None:
@@ -91,8 +98,9 @@
 
 
 def get_values(name, tiller_namespace='kube-system', tiller_host=None,
-               kube_config=None):
+               kube_config=None, gce_service_token=None):
     cmd = _helm_cmd('get', 'values', '--all', name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
-                    kube_config=kube_config)
+                    kube_config=kube_config,
+                    gce_service_token=gce_service_token)
     return yaml.deserialize(__salt__['cmd.run_stdout'](**cmd))
diff --git a/_states/helm_release.py b/_states/helm_release.py
index 464e6d6..d4a1b69 100644
--- a/_states/helm_release.py
+++ b/_states/helm_release.py
@@ -14,11 +14,12 @@
 
 def present(name, chart_name, namespace, version=None, values=None,
             tiller_namespace='kube-system', tiller_host=None,
-            kube_config=None):
+            kube_config=None, gce_service_token=None):
     tiller_args = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
+        'gce_service_token': gce_service_token,
     }
     exists = __salt__['helm.release_exists'](name, namespace, **tiller_args)
     if not exists:
@@ -61,11 +62,12 @@
 
 
 def absent(name, namespace, tiller_namespace='kube-system', tiller_host=None,
-           kube_config=None):
+           kube_config=None, gce_service_token=None):
     tiller_args = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
+        'gce_service_token': gce_service_token,
     }
     exists = __salt__['helm.release_exists'](name, namespace, **tiller_args)
     if not exists:
diff --git a/helm/client.sls b/helm/client.sls
index 07b3d3d..3fb2c8b 100644
--- a/helm/client.sls
+++ b/helm/client.sls
@@ -5,6 +5,18 @@
 {%- set helm_bin = "/usr/bin/helm-" + client.version %}
 {%- set kubectl_bin = "/usr/bin/kubectl" %}
 {%- set kube_config = "/srv/helm/kubeconfig.yaml" %}
+
+{%- if client.kubectl.config.gce_service_token %}
+{%- set gce_service_token = "/srv/helm/gce_token.json" %}
+{%- set gce_env_var = "- GOOGLE_APPLICATION_CREDENTIALS: \"{}\"".format(gce_service_token) %}
+{%- set gce_state_arg = "- gce_service_token: \"{}\"".format(gce_service_token) %}
+{%- set gce_require = "- file: \"{}\"".format(gce_service_token) %}
+{%- else %}
+{%- set gce_env_var = "" %}
+{%- set gce_state_arg = "" %}
+{%- set gce_require = "" %}
+{%- endif %}
+
 {%- set helm_home = "/srv/helm/home" %}
 {%- if client.tiller.host %}
 {%- set helm_run = "helm --host '{}'".format(client.tiller.host) %}
@@ -63,6 +75,18 @@
     - group: root
     - template: jinja
 
+{%- if client.kubectl.config.gce_service_token %}
+{{ gce_service_token }}:
+  file.managed:
+    - source: salt://helm/files/gce_token.json.j2
+    - mode: 400
+    - user: root
+    - group: root
+    - template: jinja
+    - context:
+        content: {{ client.kubectl.config.gce_service_token }}
+{%- endif %}
+
 {%- if client.tiller.install %}
 install_tiller:
   cmd.run:
@@ -70,10 +94,12 @@
     - env:
       - HELM_HOME: {{ helm_home }}
       - KUBECONFIG: {{ kube_config }}
+      {{ gce_env_var }}
     - unless: "{{ helm_run }} version --server --short | grep -E 'Server: v{{ client.version }}(\\+|$)'"
     - require:
       - cmd: prepare_client
       - file: {{ kube_config }}
+      {{ gce_require }}
 
 wait_for_tiller:
   cmd.run:
@@ -81,8 +107,10 @@
     - env:
       - HELM_HOME: {{ helm_home }}
       - KUBECONFIG: {{ kube_config }}
+      {{ gce_env_var }}
     - require:
       - file: {{ kube_config }}
+      {{ gce_require }}
     - onchanges:
       - cmd: install_tiller
 {%- endif %}
@@ -110,6 +138,7 @@
     - namespace: {{ namespace }}
     - kube_config: {{ kube_config }}
     {{ tiller_arg }}
+    {{ gce_state_arg }}
     {%- if release.get('version') %}
     - version: {{ release['version'] }}
     {%- endif %}
@@ -122,6 +151,7 @@
       - cmd: wait_for_tiller
 {%- endif %}
       - cmd: ensure_{{ namespace }}_namespace
+      {{ gce_require }}
     {%- do namespaces.append(namespace) %}
 {%- else %}{# not release.enabled #}
 absent_{{ release_id }}_release:
@@ -130,10 +160,12 @@
     - namespace: {{ namespace }}
     - kube_config: {{ kube_config }}
     {{ tiller_arg }}
+    {{ gce_state_arg }}
     - require:
 {%- if client.tiller.install %}
       - cmd: wait_for_tiller
 {%- endif %}
+      {{ gce_require }}
       - cmd: prepare_client
 {%- endif %}{# release.enabled #}
 {%- endfor %}{# release_id, release in client.releases #}
@@ -171,8 +203,10 @@
     - unless: kubectl get namespace {{ namespace }}
     - env:
       - KUBECONFIG: {{ kube_config }}
+      {{ gce_env_var }}
     - require:
       - file: {{ kube_config }}
+      {{ gce_require }}
     {%- if client.kubectl.install %}
       - file: {{ kubectl_bin }}
     {%- endif %}
diff --git a/helm/files/gce_token.json.j2 b/helm/files/gce_token.json.j2
new file mode 100644
index 0000000..77bf953
--- /dev/null
+++ b/helm/files/gce_token.json.j2
@@ -0,0 +1 @@
+{{- salt['hashutil.base64_b64decode'](content) -}}
diff --git a/metadata/service/client.yml b/metadata/service/client.yml
index 1822dd8..ccd42f7 100644
--- a/metadata/service/client.yml
+++ b/metadata/service/client.yml
@@ -21,5 +21,6 @@
         config:
           cluster: {}
           user: {}
+          gce_service_token:
       repos: {}
       releases: {}