diff options
Diffstat (limited to 'docs')
-rwxr-xr-x | docs/dckrman.sh | 5 | ||||
-rw-r--r-- | docs/source/markdown/podman-auto-update.1.md | 46 | ||||
-rw-r--r-- | docs/source/markdown/podman-commit.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-create.1.md | 16 | ||||
-rw-r--r-- | docs/source/markdown/podman-restart.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman-run.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-stop.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-version.1.md | 2 | ||||
-rw-r--r-- | docs/source/markdown/podman.1.md | 10 | ||||
-rw-r--r-- | docs/tutorials/README.md | 4 | ||||
-rw-r--r-- | docs/tutorials/image_signing.md | 194 |
11 files changed, 270 insertions, 21 deletions
diff --git a/docs/dckrman.sh b/docs/dckrman.sh index 8ae7fd40d..c69524a7e 100755 --- a/docs/dckrman.sh +++ b/docs/dckrman.sh @@ -1,5 +1,6 @@ #!/bin/sh for i in $@; do - filename=$(echo $i | sed 's/podman/docker/g') - echo .so man1/$i > $filename + b=$(basename $i) + filename=$(echo $i | sed 's/podman/docker/g') + echo .so man1/$b > $filename done diff --git a/docs/source/markdown/podman-auto-update.1.md b/docs/source/markdown/podman-auto-update.1.md new file mode 100644 index 000000000..93ad22f76 --- /dev/null +++ b/docs/source/markdown/podman-auto-update.1.md @@ -0,0 +1,46 @@ +% podman-auto-update(1) + +## NAME +podman-auto-update - Auto update containers according to their auto-update policy + +## SYNOPSIS +**podman auto-update** + +## DESCRIPTION +`podman auto-update` looks up containers with a specified "io.containers.autoupdate" label (i.e., the auto-update policy). + +If the label is present and set to "image", Podman reaches out to the corresponding registry to check if the image has been updated. +An image is considered updated if the digest in the local storage is different than the one of the remote image. +If an image must be updated, Podman pulls it down and restarts the systemd unit executing the container. + +At container-creation time, Podman looks up the "PODMAN_SYSTEMD_UNIT" environment variables and stores it verbatim in the container's label. +This variable is now set by all systemd units generated by `podman-generate-systemd` and is set to `%n` (i.e., the name of systemd unit starting the container). +This data is then being used in the auto-update sequence to instruct systemd (via DBUS) to restart the unit and hence to restart the container. + +Note that `podman auto-update` relies on systemd and requires a fully-qualified image reference (e.g., quay.io/podman/stable:latest) to be used to create the container. +This enforcement is necessary to know which image to actually check and pull. +If an image ID was used, Podman would not know which image to check/pull anymore. + +## EXAMPLES + +``` +# Start a container +$ podman run -d busybox:latest top +bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d + +# Generate a systemd unit for this container +$ podman generate systemd --new --files bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d +/home/user/containers/libpod/container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service + +# Load the new systemd unit and start it +$ mv ./container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service ~/.config/systemd/user +$ systemctl --user daemon-reload +$ systemctl --user start container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service + +# Auto-update the container +$ podman auto-update +container-bc219740a210455fa27deacc96d50a9e20516492f1417507c13ce1533dbdcd9d.service +``` + +## SEE ALSO +podman(1), podman-generate-systemd(1), podman-run(1), systemd.unit(5) diff --git a/docs/source/markdown/podman-commit.1.md b/docs/source/markdown/podman-commit.1.md index 2f1369847..13e46a899 100644 --- a/docs/source/markdown/podman-commit.1.md +++ b/docs/source/markdown/podman-commit.1.md @@ -38,6 +38,10 @@ Can be set multiple times Set the format of the image manifest and metadata. The currently supported formats are _oci_ and _docker_. If not specifically set, the default format used is _oci_. +**--iidfile**=*ImageIDfile* + +Write the image ID to the file. + **--include-volumes** Include in the committed image any volumes added to the container by the `--volume` or `--mount` options to the `podman create` and `podman run` commands. diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md index aa2456836..38b95edc3 100644 --- a/docs/source/markdown/podman-create.1.md +++ b/docs/source/markdown/podman-create.1.md @@ -44,7 +44,7 @@ each of stdin, stdout, and stderr. **--authfile**=*path* -Path of the authentication file. Default is ${XDG_\RUNTIME\_DIR}/containers/auth.json +Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json Note: You can also override the default path of the authentication file by setting the REGISTRY\_AUTH\_FILE environment variable. `export REGISTRY_AUTH_FILE=path` (Not available for remote commands) @@ -70,8 +70,8 @@ Drop Linux capabilities Set the cgroup namespace mode for the container. **host**: use the host's cgroup namespace inside the container. **container:<NAME|ID>**: join the namespace of the specified container. - **private**: create a new cgroup namespace. **ns:<PATH>**: join the namespace at the specified path. + **private**: create a new cgroup namespace. If the host uses cgroups v1, the default is set to **host**. On cgroups v2 the default is **private**. @@ -550,6 +550,7 @@ Valid values are: - `host`: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure. - `<network-name>|<network-id>`: connect to a user-defined network, multiple networks should be comma separated - `ns:<path>`: path to a network namespace to join +- `private`: create a new namespace for the container (default) - `slirp4netns`: use slirp4netns to create a user network stack. This is the default for rootless containers **--network-alias**=*alias* @@ -579,9 +580,10 @@ Tune the host's OOM preferences for containers (accepts -1000 to 1000) Set the PID mode for the container Default is to create a private PID namespace for the container - 'container:<name|id>': join another container's PID namespace - 'host': use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure. - 'ns': join the specified PID namespace +- `container:<name|id>`: join another container's PID namespace +- `host`: use the host's PID namespace for the container. Note: the host mode gives the container full access to local PID and is therefore considered insecure. +- `ns`: join the specified PID namespace +- `private`: create a new namespace for the container (default) **--pids-limit**=*limit* @@ -824,14 +826,16 @@ Without this argument the command will be run as root in the container. **--userns**=*host* **--userns**=*keep-id* **--userns**=container:container +**--userns**=private **--userns**=*ns:my_namespace* Set the user namespace mode for the container. It defaults to the **PODMAN_USERNS** environment variable. An empty value means user namespaces are disabled. +- `container`: join the user namespace of the specified container. - `host`: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user. - `keep-id`: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user. - `ns`: run the container in the given existing user namespace. -- `container`: join the user namespace of the specified container. +- `private`: create a new namespace for the container (default) This option is incompatible with --gidmap, --uidmap, --subuid and --subgid diff --git a/docs/source/markdown/podman-restart.1.md b/docs/source/markdown/podman-restart.1.md index 6507530e1..247d50685 100644 --- a/docs/source/markdown/podman-restart.1.md +++ b/docs/source/markdown/podman-restart.1.md @@ -26,7 +26,7 @@ The latest option is not supported on the remote client. **--running** Restart all containers that are already in the *running* state. -**-t**, **--time**, **--timeout**=*time* +**-t**, **--time**=*time* Timeout to wait before forcibly stopping the container. diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 3225654b6..e8b7d56b7 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -561,6 +561,7 @@ Valid _mode_ values are: - **host**: use the Podman host network stack. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure; - _network-id_: connect to a user-defined network, multiple networks should be comma separated; - **ns:**_path_: path to a network namespace to join; +- `private`: create a new namespace for the container (default) - **slirp4netns**: use **slirp4netns**(1) to create a user network stack. This is the default for rootless containers. **--network-alias**=*alias* @@ -594,6 +595,7 @@ The efault is to create a private PID namespace for the container. - **container:**_id_: join another container's PID namespace; - **host**: use the host's PID namespace for the container. Note the host mode gives the container full access to local PID and is therefore considered insecure; +- **private**: create a new namespace for the container (default) - **ns:**_path_: join the specified PID namespace. **--pids-limit**=*limit* @@ -867,6 +869,7 @@ Set the user namespace mode for the container. It defaults to the **PODMAN_USER - **host**: run in the user namespace of the caller. This is the default if no user namespace options are set. The processes running in the container will have the same privileges on the host as any other process launched by the calling user. - **keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is ignored for containers created by the root user. - **ns**: run the container in the given existing user namespace. +- **private**: create a new namespace for the container (default) - **container**: join the user namespace of the specified container. This option is incompatible with **--gidmap**, **--uidmap**, **--subuid** and **--subgid**. @@ -876,6 +879,7 @@ This option is incompatible with **--gidmap**, **--uidmap**, **--subuid** and ** Set the UTS namespace mode for the container. The following values are supported: - **host**: use the host's UTS namespace inside the container. +- **private**: create a new namespace for the container (default) - **ns**: use own UTS namespace. **NOTE**: the host mode gives the container access to changing the host's hostname and is therefore considered insecure. diff --git a/docs/source/markdown/podman-stop.1.md b/docs/source/markdown/podman-stop.1.md index 7dbf18887..23b3415e9 100644 --- a/docs/source/markdown/podman-stop.1.md +++ b/docs/source/markdown/podman-stop.1.md @@ -38,9 +38,9 @@ to run containers such as CRI-O, the last started container could be from either The latest option is not supported on the remote client. -**--timeout**, **--time**, **-t**=*time* +**--time**, **-t**=*time* -Timeout to wait before forcibly stopping the container +Time to wait before forcibly stopping the container ## EXAMPLES diff --git a/docs/source/markdown/podman-version.1.md b/docs/source/markdown/podman-version.1.md index de22c4800..86c270e02 100644 --- a/docs/source/markdown/podman-version.1.md +++ b/docs/source/markdown/podman-version.1.md @@ -7,7 +7,7 @@ podman\-version - Display the Podman version information **podman version** [*options*] ## DESCRIPTION -Shows the following information: Version, Go Version, Git Commit, Build Time, +Shows the following information: Remote API Version, Version, Go Version, Git Commit, Build Time, OS, and Architecture. ## OPTIONS diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 86d246e87..cd4148c95 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -31,18 +31,9 @@ Note: CGroup manager is not supported in rootless mode when using CGroups Versio **--cni-config-dir** Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d`) -**--config** -Path of a libpod config file detailing container server configuration options - -Default libpod config file is /usr/share/containers/libpod.conf. Override file is in /etc/containers/libpod.conf. In rootless mode the config file will be read from $HOME/.config/containers/libpod.conf. - **--conmon** Path of the conmon binary (Default path is configured in `libpod.conf`) -**--cpu-profile**=*path* - -Path to where the cpu performance results should be written - **--events-backend**=*type* Backend to use for storing events. Allowed values are **file**, **journald**, and **none**. @@ -154,6 +145,7 @@ the exit codes follow the `chroot` standard, see below: | Command | Description | | ------------------------------------------------ | --------------------------------------------------------------------------- | | [podman-attach(1)](podman-attach.1.md) | Attach to a running container. | +| [podman-auto-update(1)](podman-auto-update.1.md) | Auto update containers according to their auto-update policy | | [podman-build(1)](podman-build.1.md) | Build a container image using a Containerfile. | | [podman-commit(1)](podman-commit.1.md) | Create new image based on the changed container. | | [podman-container(1)](podman-container.1.md) | Manage containers. | diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index bcd1b01d9..191d7a4b5 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -23,3 +23,7 @@ A brief how-to on using the Podman remote-client. **[How to use libpod for custom/derivative projects](podman-derivative-api.md)** How the libpod API can be used within your own project. + +**[Image Signing](image_signing.md)** + +Learn how to setup and use image signing with Podman. diff --git a/docs/tutorials/image_signing.md b/docs/tutorials/image_signing.md new file mode 100644 index 000000000..f0adca9af --- /dev/null +++ b/docs/tutorials/image_signing.md @@ -0,0 +1,194 @@ +# How to sign and distribute container images using Podman + +Signing container images originates from the motivation of trusting only +dedicated image providers to mitigate man-in-the-middle (MITM) attacks or +attacks on container registries. One way to sign images is to utilize a GNU +Privacy Guard ([GPG][0]) key. This technique is generally compatible with any +OCI compliant container registry like [Quay.io][1]. It is worth mentioning that +the OpenShift integrated container registry supports this signing mechanism out +of the box, which makes separate signature storage unnecessary. + +[0]: https://gnupg.org +[1]: https://quay.io + +From a technical perspective, we can utilize Podman to sign the image before +pushing it into a remote registry. After that, all systems running Podman have +to be configured to retrieve the signatures from a remote server, which can +be any simple web server. This means that every unsigned image will be rejected +during an image pull operation. But how does this work? + +First of all, we have to create a GPG key pair or select an already locally +available one. To generate a new GPG key, just run `gpg --full-gen-key` and +follow the interactive dialog. Now we should be able to verify that the key +exists locally: + +```bash +> gpg --list-keys sgrunert@suse.com +pub rsa2048 2018-11-26 [SC] [expires: 2020-11-25] + XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +uid [ultimate] Sascha Grunert <sgrunert@suse.com> +sub rsa2048 2018-11-26 [E] [expires: 2020-11-25] +``` + +Now let’s assume that we run a container registry. For example we could simply +start one on our local machine: + +```bash +> sudo podman run -d -p 5000:5000 docker.io/registry +``` + +The registry does not know anything about image signing, it just provides the remote +storage for the container images. This means if we want to sign an image, we +have to take care of how to distribute the signatures. + +Let’s choose a standard `alpine` image for our signing experiment: + +```bash +> sudo podman pull docker://docker.io/alpine:latest +``` + +```bash +> sudo podman images alpine +REPOSITORY TAG IMAGE ID CREATED SIZE +docker.io/library/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB +``` + +Now we can re-tag the image to point it to our local registry: + +```bash +> sudo podman tag alpine localhost:5000/alpine +``` + +```bash +> sudo podman images alpine +REPOSITORY TAG IMAGE ID CREATED SIZE +localhost:5000/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB +docker.io/library/alpine latest e7d92cdc71fe 6 weeks ago 5.86 MB +``` + +Podman would now be able to push the image and sign it in one command. But to +let this work, we have to modify our system-wide registries configuration at +`/etc/containers/registries.d/default.yaml`: + +```yaml +default-docker: + sigstore: http://localhost:8000 # Added by us + sigstore-staging: file:///var/lib/containers/sigstore +``` + +We can see that we have two signature stores configured: + +- `sigstore`: referencing a web server for signature reading +- `sigstore-staging`: referencing a file path for signature writing + +Now, let’s push and sign the image: + +```bash +> sudo -E GNUPGHOME=$HOME/.gnupg \ + podman push \ + --tls-verify=false \ + --sign-by sgrunert@suse.com \ + localhost:5000/alpine +… +Storing signatures +``` + +If we now take a look at the systems signature storage, then we see that there +is a new signature available, which was caused by the image push: + +```bash +> sudo ls /var/lib/containers/sigstore +'alpine@sha256=e9b65ef660a3ff91d28cc50eba84f21798a6c5c39b4dd165047db49e84ae1fb9' +``` + +The default signature store in our edited version of +`/etc/containers/registries.d/default.yaml` references a web server listening at +`http://localhost:8000`. For our experiment, we simply start a new server inside +the local staging signature store: + +```bash +> sudo bash -c 'cd /var/lib/containers/sigstore && python3 -m http.server' +Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... +``` + +Let’s remove the local images for our verification test: + +``` +> sudo podman rmi docker.io/alpine localhost:5000/alpine +``` + +We have to write a policy to enforce that the signature has to be valid. This +can be done by adding a new rule in `/etc/containers/policy.json`. From the +below example, copy the `"docker"` entry into the `"transports"` section of your +`policy.json`. + +```json +{ + "default": [{ "type": "insecureAcceptAnything" }], + "transports": { + "docker": { + "localhost:5000": [ + { + "type": "signedBy", + "keyType": "GPGKeys", + "keyPath": "/tmp/key.gpg" + } + ] + } + } +} +``` + +The `keyPath` does not exist yet, so we have to put the GPG key there: + +```bash +> gpg --output /tmp/key.gpg --armor --export sgrunert@suse.com +``` + +If we now pull the image: + +```bash +> sudo podman pull --tls-verify=false localhost:5000/alpine +… +Storing signatures +e7d92cdc71feacf90708cb59182d0df1b911f8ae022d29e8e95d75ca6a99776a +``` + +Then we can see in the logs of the web server that the signature has been +accessed: + +``` +127.0.0.1 - - [04/Mar/2020 11:18:21] "GET /alpine@sha256=e9b65ef660a3ff91d28cc50eba84f21798a6c5c39b4dd165047db49e84ae1fb9/signature-1 HTTP/1.1" 200 - +``` + +As an counterpart example, if we specify the wrong key at `/tmp/key.gpg`: + +```bash +> gpg --output /tmp/key.gpg --armor --export mail@saschagrunert.de +File '/tmp/key.gpg' exists. Overwrite? (y/N) y +``` + +Then a pull is not possible any more: + +```bash +> sudo podman pull --tls-verify=false localhost:5000/alpine +Trying to pull localhost:5000/alpine... +Error: error pulling image "localhost:5000/alpine": unable to pull localhost:5000/alpine: unable to pull image: Source image rejected: Invalid GPG signature: … +``` + +So in general there are four main things to be taken into consideration when +signing container images with Podman and GPG: + +1. We need a valid private GPG key on the signing machine and corresponding + public keys on every system which would pull the image +2. A web server has to run somewhere which has access to the signature storage +3. The web server has to be configured in any + `/etc/containers/registries.d/*.yaml` file +4. Every image pulling system has to be configured to contain the enforcing + policy configuration via `policy.conf` + +That’s it for image signing and GPG. The cool thing is that this setup works out +of the box with [CRI-O][2] as well and can be used to sign container images in +Kubernetes environments. + +[2]: https://cri-o.io |