3

I'm trying to write an ansible role that first does a docker login to a GCE instance before pulling images from the container registry. I need to do this because of the problem mentioned here.

First I tried the code block below

- name: Docker Login
  docker_login:
    registry: https://eu.gcr.io
    username: _json_key
    debug: true
    password: "{{ lookup('file', 'pulse-psg-863d9955d8a1.json')}}"

The error I get with this is (private key modified)

fatal: [en1-a-sftp-delivery-0]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "api_version": null,
            "cacert_path": null,
            "cert_path": null,
            "config_path": "~/.docker/config.json",
            "debug": true,
            "docker_host": null,
            "email": null,
            "filter_logger": false,
            "key_path": null,
            "password": "{'private_key': '-----BEGIN PRIVATE KEY-----\\vU5K1MuTpTQGEzg\\nuywOlHw7ZLEj4u65vxrnzpiCOw6Pu7IVZq9R2JPhAoGAFnpxIA4RxuB7cRIOU6EY\\naqBaHT73gmw8ulCHYSUWw+/P9ZquFjsnF8p7hzZ8pCOMSUwaLCQaDfqZvfcEoMqI\\naz9cOJdyjsZjOb1DLd2YtLCUNWldu5Nmh621L51bNh+clYpiSwOnD+ZhN5jrkIK9\\nleeCdUVeg71+h2gzKJGHJBU=\\n-----END PRIVATE KEY-----\\n', 'private_key_id': '********', 'token_uri': '********', 'auth_provider_x509_cert_url': '********', 'auth_uri': '********', 'client_email': '********', 'client_id': '********', 'project_id': '********', 'type': '********', 'client_x509_cert_url': '********'}",
            "reauthorize": false,
            "registry": "https://eu.gcr.io",
            "registry_url": "https://eu.gcr.io",
            "ssl_version": null,
            "state": "present",
            "timeout": null,
            "tls": null,
            "tls_hostname": null,
            "tls_verify": null,
            "username": "_json_key"
        }
    },
    "msg": "Logging into https://eu.gcr.io for user _json_key failed - 500 Server Error: Internal Server Error (\"{\"message\":\"Get https://eu.gcr.io/v2/: unknown: Unable to parse json key.\"}\")"
}

I couldn't for the life of me get it to parse the private key. I suspect it's got something to do either with the asterisk characters (I don't know if that's only ansible masking it in the debug output or whether that's what is being sent onwards) or the \n character.

I tried therefore to login to the GCE machine and try the command from the command line as shown in the second answer here. So first I scp'd the keyfile onto the machine and then:

JSON_KEY=$(cat keyfile.json)
sudo docker login  -u _json_key -p "$JSON_KEY" https://gcr.io

This worked with a few warnings but I was able to login and pull images thereafter. I concluded that it's an issue with the docker login ansible module and so decided to try a shell command instead. So:

- name: Docker Login using shell
  shell: docker login -u _json_key -p "{{ lookup('file', 'keyfile.json') |  replace('\n', '')}}" http://eu.gcr.io

This does not succeed either

snip
 "module_args": {
            "_raw_params": "docker login -u _json_key -p \"{\n  \"type\": \"service_account\",\n  \"project_id\": \"id\",\n  \"private_key_id\": \"863d9955d8a1e5e04a15b36ef80a787bc2\",\n  \"private_key\": \"-----BEGIN PRIVATE KEY-----MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2Z7c33lnCQDXFssGvg0t9xi9Aqk6x4cazQPUJ8j0Y+qWDBPL+ShHNSZwVykmAugC51KKInm5ik4IWTA5ict3VBRnWiutdxQK++icZ2yCuFlPMDFp2g2GQ4wl8bH1X3AtWgHO/nSWD3Rle7M/p9CUJq3K1EA07H9GKBJZmfGaoc4HA+OG8/j2Q7i8KmG9pFjKOAlQsHPdKKZqn4YeHPOTmARJgxw6PXbchAp+nPA7f7hpbmaK3XRNRxuB7cRIOU6EYaqBaHT73gmw8ulCHYSUWw+/P9ZquFjsnF8p7hzZ8pCOMSUwaLCQaDfqZvfcEoMqIaz9cOJdyjsZjOb1DLd2YtLCUNWldu5Nmh621L51bNh+clYpiSwOnD+ZhN5jrkIK9leeCdUVeg71+h2gzKJGHJBU=-----END PRIVATE KEY-----\",\n  \"client_email\": \"duh-compute@developer.gserviceaccount.com\",\n  \"client_id\": \"1115155168041\",\n  \"auth_uri\": \"https://accounts.google.com/o/oauth2/auth\",\n  \"token_uri\": \"https://oauth2.googleapis.com/token\",\n  \"auth_provider_x509_cert_url\": \"https://www.googleapis.com/oauth2/v1/certs\",\n  \"client_x509_cert_url\": \"https://www.googleapis.com/robot/v1/metadata/x509/879255832886-compute%40developer.gserviceaccount.com\"\n}\" http://eu.gcr.io",
            "_uses_shell": true,
            "chdir": null,
            "creates": null,
            "executable": null,
            "removes": null,
            "stdin": null,
            "warn": true
        }
msg": "non-zero return code",
    "rc": 1,
    "start": "2019-07-29 18:31:55.246592",
    "stderr": "\"docker login\" requires at most 1 argument.\nSee 'docker login --help'.\n\nUsage:  docker login [OPTIONS] [SERVER]\n\nLog in to a Docker registry",
    "stderr_lines": [
        "\"docker login\" requires at most 1 argument.",
        "See 'docker login --help'.",
        "",
        "Usage:  docker login [OPTIONS] [SERVER]",
        "",
        "Log in to a Docker registry"
    ],
SNIP

This again I suspect is because it does not like the format of the key but this time it's the docker login command rather than the remote server (as in the earlier case) where atleast the key was transmitted. In both cases the challenge seems to be to get a key stored in JSON format in a file transmitted without any extra characters as one would do when one refers to the environment variable when running the command directly on the command line.

I've spent the better part of 3 days now trying to automate having a GCE instance and making it work with docker something that should be fairly trivial.

Devu
  • 381
  • 3
  • 15
  • For the record what worked for me is `docker_login: registry: https://eu.gcr.io username: _json_key password: " {{ lookup('password', 'pulse-psg-863d9955d8a1.json') }}"` Notice the space after the quotes and before the beginning curly brace. – Devu Jul 30 '19 at 09:15

1 Answers1

3

lookup is interpreting your json badly.

Solution is to insert space to the beginning of the password string password: " {{ lookup('file', 'pulse-psg-863d9955d8a1.json')}}"

Thyrst'
  • 2,253
  • 2
  • 22
  • 27
  • Bingo It works. This is magic. Do you mind explaining what the space actually does to make it work and if you could link to some documentation explaining it? Also a side note that trying the same approach (adding space) with the shell module `shell: docker login -u _json_key -p " {{ lookup('file', 'pulse-psg-863d9955d8a1.json')}}" http://eu.gcr.io` does not work. So this is even more mysterious. Perhaps the space means something to the `docker login` module – Devu Jul 30 '19 at 09:12
  • 2
    @Devu There is some dude from Ansible team explaining it: https://groups.google.com/d/msg/ansible-devel/2C7pl2_kxlY/Mjbki7wKAwAJ – Thyrst' Jul 30 '19 at 11:09
  • Hmm..Indeed my JSON is object like and starts with the "{" character. I had read this and other such posts but after 3 days of banging my head with GCE and other issues was too tired to catch this. Your succinct one-liner worked better. I'm not sure they've fixed it yet. I'd much rather remove the hack of having a space. There's something mentioned around `"{{ lookup('template','./bucket-public.json.j2', convert_data=False) |string}}"` but I don't see any option for a simple file lookup. Specifying the type=json or something similar would be much cleaner but I don't see such an option yet. – Devu Jul 30 '19 at 13:22
  • Also some conversation about it [here](https://github.com/ansible/ansible/issues/15603) – Devu Jul 30 '19 at 13:39