ansible / ansible-container

DEPRECATED -- Ansible Container was a tool to build Docker images and orchestrate containers using only Ansible playbooks.
GNU Lesser General Public License v3.0
2.19k stars 394 forks source link

ansible-container build: Conductor container fails when using user namespaces #967

Open KajdeMunter opened 5 years ago

KajdeMunter commented 5 years ago
ISSUE TYPE
container.yml
...
settings:
  conductor:
    base: alpine:3.5
...
OS / ENVIRONMENT
Ansible Container, version 0.9.2
Linux, MacBookPro, 4.15.0-33-generic, #36-Ubuntu SMP Wed Aug 15 16:00:05 UTC 2018, x86_64
2.7.15rc1 (default, Apr 15 2018, 21:51:34) 
[GCC 7.3.0] /usr/bin/python
{
  "ContainersPaused": 0, 
  "Labels": [], 
  "CgroupDriver": "cgroupfs", 
  "ContainersRunning": 0, 
  "ContainerdCommit": {
    "Expected": "773c489c9c1b21a6d78b5c538cd395416ec50f88", 
    "ID": "773c489c9c1b21a6d78b5c538cd395416ec50f88"
  }, 
  "InitBinary": "docker-init", 
  "NGoroutines": 34, 
  "Swarm": {
    "ControlAvailable": false, 
    "NodeID": "", 
    "Error": "", 
    "RemoteManagers": null, 
    "LocalNodeState": "inactive", 
    "NodeAddr": ""
  }, 
  "LoggingDriver": "json-file", 
  "OSType": "linux", 
  "HttpProxy": "", 
  "Runtimes": {
    "runc": {
      "path": "docker-runc"
    }
  }, 
  "DriverStatus": [
    [
      "Backing Filesystem", 
      "extfs"
    ], 
    [
      "Supports d_type", 
      "true"
    ], 
    [
      "Native Overlay Diff", 
      "true"
    ]
  ], 
  "OperatingSystem": "Ubuntu 18.04.1 LTS", 
  "Containers": 0, 
  "HttpsProxy": "", 
  "BridgeNfIp6tables": true, 
  "MemTotal": 8268759040, 
  "SecurityOptions": [
    "name=apparmor", 
    "name=seccomp,profile=default", 
    "name=userns"
  ], 
  "Driver": "overlay2", 
  "IndexServerAddress": "https://index.docker.io/v1/", 
  "ClusterStore": "", 
  "InitCommit": {
    "Expected": "949e6fa", 
    "ID": "949e6fa"
  }, 
  "GenericResources": null, 
  "Isolation": "", 
  "SystemStatus": null, 
  "OomKillDisable": true, 
  "ClusterAdvertise": "", 
  "SystemTime": "2018-09-14T14:48:05.445818653+02:00", 
  "Name": "kaj-MacBookPro", 
  "CPUSet": true, 
  "RegistryConfig": {
    "AllowNondistributableArtifactsCIDRs": [], 
    "Mirrors": [], 
    "IndexConfigs": {
      "docker.io": {
        "Official": true, 
        "Name": "docker.io", 
        "Secure": true, 
        "Mirrors": []
      }
    }, 
    "AllowNondistributableArtifactsHostnames": [], 
    "InsecureRegistryCIDRs": [
      "127.0.0.0/8"
    ]
  }, 
  "DefaultRuntime": "runc", 
  "ContainersStopped": 0, 
  "NCPU": 4, 
  "NFd": 20, 
  "Architecture": "x86_64", 
  "KernelMemory": true, 
  "CpuCfsQuota": true, 
  "Debug": false, 
  "ID": "6ZID:HBNY:HAQ2:VK6F:NGND:HVKM:DYNA:2AHJ:DI2K:KB7T:TKXN:4YUS", 
  "IPv4Forwarding": true, 
  "KernelVersion": "4.15.0-33-generic", 
  "BridgeNfIptables": true, 
  "NoProxy": "", 
  "LiveRestoreEnabled": false, 
  "ServerVersion": "18.03.1-ce", 
  "CpuCfsPeriod": true, 
  "ExperimentalBuild": false, 
  "MemoryLimit": true, 
  "SwapLimit": false, 
  "Plugins": {
    "Volume": [
      "local"
    ], 
    "Network": [
      "bridge", 
      "host", 
      "macvlan", 
      "null", 
      "overlay"
    ], 
    "Authorization": null, 
    "Log": [
      "awslogs", 
      "fluentd", 
      "gcplogs", 
      "gelf", 
      "journald", 
      "json-file", 
      "logentries", 
      "splunk", 
      "syslog"
    ]
  }, 
  "Images": 7, 
  "DockerRootDir": "/var/lib/docker/1000.1000", 
  "NEventsListener": 0, 
  "CPUShares": true, 
  "RuncCommit": {
    "Expected": "4fc53a81fb7c994640722ac585fa9ca548971871", 
    "ID": "4fc53a81fb7c994640722ac585fa9ca548971871"
  }
}
{
  "KernelVersion": "4.15.0-33-generic", 
  "Components": [
    {
      "Version": "18.03.1-ce", 
      "Name": "Engine", 
      "Details": {
        "KernelVersion": "4.15.0-33-generic", 
        "Os": "linux", 
        "BuildTime": "2018-06-20T21:42:00.000000000+00:00", 
        "ApiVersion": "1.37", 
        "MinAPIVersion": "1.12", 
        "GitCommit": "9ee9f40", 
        "Arch": "amd64", 
        "Experimental": "false", 
        "GoVersion": "go1.9.5"
      }
    }
  ], 
  "Arch": "amd64", 
  "BuildTime": "2018-06-20T21:42:00.000000000+00:00", 
  "ApiVersion": "1.37", 
  "Platform": {
    "Name": ""
  }, 
  "Version": "18.03.1-ce", 
  "MinAPIVersion": "1.12", 
  "GitCommit": "9ee9f40", 
  "Os": "linux", 
  "GoVersion": "go1.9.5"
}
SUMMARY

ansible-container build fails when using user namespaces. The conductor container is being run privileged but we cannot add userns_mode: "host" to the conductor. "privileged mode is incompatible with user namespaces. You must run the container in the host namespace when running privileged mode".

STEPS TO REPRODUCE

Enable userns remap on the daemon: https://docs.docker.com/engine/security/userns-remap/#enable-userns-remap-on-the-daemon

Run:

ansible-container build
EXPECTED RESULTS

ansible-container build executes succesfully

ACTUAL RESULTS
ansible-container build
Building Docker Engine context...   
Starting Docker build of Ansible Container Conductor image (please be patient)...   
ERROR   Unknown exception   
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/container/cli.py", line 299, in __call__
    getattr(core, u'hostcmd_{}'.format(args.subcommand))(**vars(args))
  File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
    return fn(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/core.py", line 201, in hostcmd_build
    'build', dict(config), base_path, kwargs, save_container=save_container)
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 454, in await_conductor_command
    conductor_id = self.run_conductor(command, config, base_path, params)
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 105, in __wrapped__
    return fn(self, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
    return fn(*args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 446, in run_conductor
    reraise(*sys.exc_info())
  File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 439, in run_conductor
    **run_kwargs
  File "/usr/local/lib/python2.7/dist-packages/docker/models/containers.py", line 719, in run
    detach=detach, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/docker/models/containers.py", line 777, in create
    resp = self.client.api.create_container(**create_kwargs)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/container.py", line 450, in create_container
    return self.create_container_from_config(config, name)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/container.py", line 461, in create_container_from_config
    return self._result(res, True)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/client.py", line 228, in _result
    self._raise_for_status(response)
  File "/usr/local/lib/python2.7/dist-packages/docker/api/client.py", line 224, in _raise_for_status
    raise create_api_error_from_http_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
    raise cls(e, response=response, explanation=explanation)
APIError: 400 Client Error: Bad Request ("privileged mode is incompatible with user namespaces.  You must run the container in the host namespace when running privileged mode")
Makefile:33: recipe for target 'build' failed
make: *** [build] Error 1
Voronenko commented 5 years ago

Can you provide more details about ansible-container usage-scenario?

In it's present state it is rather logically to use it to build images and push to some registry, while handle their deployment with some other workflow.

KajdeMunter commented 5 years ago

Can you provide more details about ansible-container usage-scenario?

In it's present state it is rather logically to use it to build images and push to some registry, while handle their deployment with some other workflow.

I am trying to prevent any kind of privilege escalation on my host. I want my containers to run on an unprivileged user but there are processes within the container that need to run as root. Also I want to be able to write to files while developing.

Here is more of my container.yml if that helps

version: "2"

volumes:
  app-data:
    docker: {}
  db-data:
    docker: {}
  session-data:
    docker: {}

defaults:
  SERVER_NAME: servername
  APP_ROOT: /var/www/html
  HTTP_PORT: 80
  HTTPS_PORT: 443
  USER_UID: 9002
  GROUP_GID: 9002
  RELEASE: '0.2'
settings:
  conductor:
    base: alpine:3.5
    project_name: projectname

  vault_password_file: '../vaultpwd'
  vault_files:
    - vault.yml
services:
  code:
    from: alpine:latest
    roles:
      - role: users
        users:
          - user: developer
            group: developer
            shell: /bin/sh
            uid: "{{ USER_UID }}"
            gid: "{{ GROUP_GID }}"
      - role: checkout
        git_repo_uri: git@bitbucket.org:repo
        git_checkout_dest: "{{ APP_ROOT }}"
        git_private_key_file: "/run/secrets/git/private_key"
        git_checkout_dest_owner: developer
        git_checkout_dest_group: developer
    working_dir: "{{ APP_ROOT }}"
#    entrypoint: ["tail", "-f", "/dev/null"]
    entrypoint: ["docker-entrypoint.sh",  "/bin/sh", "-c"]
    # TODO fix the command below to directly use {{ git_private_key_file }} when the secrets are correctly mounted
    command: ['install -m 0400 -D {{ git_private_key_file }} ~/.ssh/id_rsa && (ssh-add || (eval `ssh-agent` && ssh-add)) && ((git reset --hard origin/master && git pull) || (rm -rf ./src/ && git clone {{ git_repo_uri }} ./))']
    volumes:
      - "app-data:{{ APP_ROOT }}"
    secrets:
      git:
        - source: git_private_key
          target: private_key
          uid: "{{ USER_UID }}"
          gid: "{{ GROUP_GID }}"
          mode: 04400
    dev_overrides:
      volumes:
        - "${PWD}:{{ APP_ROOT }}:delegated"
      command: ['git pull']
......
Voronenko commented 5 years ago

My understanding, that current concept requires privileged mode, may be @j00bar can join the thread for the short explanation