In this post we’re going to focus on the container scanning functionality available through the Snyk CLI, and how that can integrate with Podman and the new Podman API which landed in Podman 2.x and is available in Red Hat Enterprise Linux 8.3. Using Snyk and the Podman API in this way provides container image scanning directly in your local command line, helping developers and admins to scan images and check for vulnerabilities right from the start of the image development process. 

What's Snyk? Snyk is a developer-first cloud native security platform that provides security insights and remediation throughout the software development lifecycle. Snyk’s integrated service covers dependency scanning for your applications across a variety of languages, security scanning for Terraform, Helm, Kubernetes, and of course container image scanning, with integrations into everything from the IDE, through source code repositories to your CI/CD and orchestration platforms.  

Getting started

The first thing we need to do is install the latest version of Podman.

[matt@localhost ~]$ sudo yum -y install podman

Next, let’s install the Snyk CLI :

[matt@localhost ~]$ sudo yum install npm
[matt@localhost ~]$ sudo npm install -g snyk

You’ll need a free Snyk account for this next bit, so go ahead and sign up here. Once you have your account set up, you can authenticate the Snyk CLI by running :

[matt@localhost ~]$ snyk auth

Firstly, let’s pull an older version of Red Hat’s Universal Base Image (UBI) from the public RedHat registry, which we know has some security vulnerabilities:

[matt@localhost ~]$ podman pull registry.access.redhat.com/ubi7/ubi:7.6
[matt@localhost ~]$ podman images
REPOSITORY                           TAG     IMAGE ID      CREATED        SIZE
registry.access.redhat.com/ubi7/ubi  7.6     247ee58855fd  15 months ago  214 MB

Since Podman is based around open standards and works with OCI-compliant images, Snyk has always been able to scan images created or pulled by Podman, by using Podman to save the image to disk and scanning it from the filesystem. Podman can save images in the Docker archive format, or in OCI archive format, both of which Snyk supports. 

[matt@localhost ~]$ podman save 247ee58855fd -o ubi76.tar
[matt@localhost ~]$ snyk container test docker-archive:ubi76.tar
Testing docker-archive:ubi76.tar...
[ TRUNCATED FOR BREVITY ]
✗ High severity vulnerability found in dbus
  Description: RHSA-2020:2894
  Info: https://snyk.io/vuln/SNYK-RHEL7-DBUS-584292
  Introduced through: dbus@1:1.10.24-13.el7_6
  From: dbus@1:1.10.24-13.el7_6
  Fixed in: 1:1.10.24-14.el7_8

Organization:      matt-jarvis-snyk
Package manager:   rpm
Project name:      docker-image|ubi76.tar
Docker image:      docker-archive:ubi76.tar
Platform:          linux/amd64
Licenses:          enabled

Tested 161 dependencies for known issues, found 68 issues.

Pro tip: use `--file` option to get base image remediation advice.
Example: $ snyk test --docker docker-archive:ubi76.tar --file=path/to/Dockerfile

To remove this message in the future, please run `snyk config set disableSuggestions=true`

Now since this is a public image in an standards compliant registry, if we want to scan this image using Snyk CLI at this point, we can also just do :

[matt@localhost ~]$ snyk container test registry.access.redhat.com/ubi7/ubi:7.6

Snyk has a built-in library for pulling from standards compliant registries, even if it doesn’t find Docker on the host. 

However, if the upstream image is in a private repository which requires a login, this won’t work because Snyk would normally use Docker to handle the registry login. This behaviour is the same even if we log in using Podman, since at this point Snyk doesn’t know how to use Podman to handle this :

[matt@localhost ~]$ podman login registry.redhat.io
[matt@localhost ~]$ snyk container test registry.redhat.io/ubi7/ubi:latest
Please login to the Red Hat Registry using your Customer Portal credentials. Further instructions can be found here: https://access.redhat.com/RegistryAuthentication

Similarly, if the image only exists locally in Podman, this will also not work, as Snyk expects to talk to a local Docker client, and at this point has no knowledge of local images in Podman. As an example, let’s tag our UBI image locally and try to scan it :

[matt@localhost ~]$ podman tag 247ee58855fd mytest
[matt@localhost ~]$ podman images
REPOSITORY                           TAG     IMAGE ID      CREATED        SIZE
registry.access.redhat.com/ubi7/ubi  7.6     247ee58855fd  15 months ago  214 MB
localhost/mytest                     latest  247ee58855fd  15 months ago  214 MB
[matt@localhost ~]$ snyk container test localhost/mytest
connect ECONNREFUSED 127.0.0.1:443

In both those use cases, Snyk would normally use the local Docker client, either through the Registry API or by using the Docker socket. Since there is no Docker binary on the system, here Snyk has attempted to use the Registry API, and failed to connect. By default Snyk doesn’t know those images exist locally in Podman, or how to use Podman to interface with upstream. 

Luckily, Podman provides us with some easy compatibility features through the podman-docker package. This gives us a fake Docker binary, which is basically just a shell wrapper to the Podman binary, and adds a symlink between the Podman API socket and the default location of the Docker socket file.  Out of the box, this package creates a symlink to /var/run/podman/podman.sock, which is the default when running the Podman API as root. 

[matt@localhost ~]$ sudo yum install podman-docker

Now let’s try and scan our local image again :

[matt@localhost ~]$ snyk container test localhost/mytest
connect ENOENT /var/run/docker.sock

Well it still doesn’t work, but this time we’ve got a different error. Snyk has detected a binary called docker, and is now trying to connect to the default location of the privileged Docker socket. Since we are not yet running the Podman API, it can’t connect and so fails again. 

Now as we saw earlier, the podman-docker package creates a symlink from /var/run/podman/podman.sock to /var/run/docker.sock, assuming that the Podman API is going to be run privileged. 

[matt@localhost ~]$ ls -l /var/run/docker.sock 
lrwxrwxrwx. 1 root root 23 Nov  3 13:19 /var/run/docker.sock -> /run/podman/podman.sock

One of the main issues with the Docker socket is that by default it runs privileged, which is considered a security risk in certain enterprise environments. For most local development environments we don’t need to run the Podman API that way, and can run an unprivileged socket somewhere else. We also have a method for communicating that location to Snyk by using the DOCKER_HOST environment variable, which supports both tcp:// and unix:// URL formats.

In a different shell, let’s run the Podman API with an unprivileged socket:

[matt@localhost ~]$ podman system service --time=0 unix://home/matt/podman.sock

This will run foregrounded, so you will have to Ctrl-C the process when finishing the test. Now we need to set the DOCKER_HOST environment variable :

[matt@localhost ~]$ export DOCKER_HOST=unix:///home/matt/podman.sock

And finally let’s try and scan our local image again with Snyk :

[matt@localhost ~]$ snyk container test localhost/mytest

Testing localhost/mytest...

[ TRUNCATED FOR BREVITY ]

✗ High severity vulnerability found in dbus
  Description: RHSA-2020:2894
  Info: https://snyk.io/vuln/SNYK-RHEL7-DBUS-584292
  Introduced through: dbus@1:1.10.24-13.el7_6
  From: dbus@1:1.10.24-13.el7_6
  Fixed in: 1:1.10.24-14.el7_8


Organization:      matt-jarvis-snyk
Package manager:   rpm
Project name:      docker-image|localhost/mytest
Docker image:      localhost/mytest
Platform:          linux/amd64
Licenses:          enabled

Tested 161 dependencies for known issues, found 68 issues.

Pro tip: use `--file` option to get base image remediation advice.
Example: $ snyk test --docker localhost/mytest --file=path/to/Dockerfile

To remove this message in the future, please run `snyk config set disableSuggestions=true`

Success! Snyk is now working correctly, and talking to Podman using an unprivileged socket.

To configure DOCKER_HOST permanently in your shell, you can add the export command to your .bashrc file which will persist the setting.

Finally we’d really like to have this whole setup automatically available to us whenever we log in. To do this we can take advantage of the socket activation facilities in systemd to automatically start our socket when we log in and try to connect to it.

First we need to configure the socket :

[matt@localhost ~]$ cat .config/systemd/user/podman.socket
[Unit]
Description=Podman API Socket
Documentation=man:podman-api(1)

[Socket]
ListenStream=/home/matt/podman.sock
SocketMode=0660

[Install]
WantedBy=sockets.target

And then tie the socket to a service :

[matt@localhost ~]$ cat .config/systemd/user/podman.service
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-api(1)
StartLimitIntervalSec=0

[Service]
Type=oneshot
Environment=REGISTRIES_CONFIG_PATH=/etc/containers/registries.conf
ExecStart=/usr/bin/podman system service unix:///home/matt/podman.sock
TimeoutStopSec=30
KillMode=process

[Install]
WantedBy=multi-user.target
Also=podman.socket

Finally we reload the systemd configuration and enable the service !

[matt@localhost ~]$ systemctl --user daemon-reload
[matt@localhost ~]$ systemctl --user enable --now podman.socket

Now whenever we log in as our local user, we have the Podman API available on demand locally from an unprivileged socket, which Snyk can connect to using the DOCKER_HOST environment variable we set earlier. 

Conclusion

So there we have it, Snyk CLI image scanning with Podman working in the same way as with Docker, allowing developers easy access to security scans of local container images as part of their development workflow. 

All of the Snyk functionality is available via the CLI, including adding images to your Snyk dashboard for ongoing monitoring. Snyk collaborates with Red Hat to help developers automate security controls in application development, delivering actionable, scalable cloud native security without compromising speed or performance. Make sure your containers are scanned for security vulnerabilities, and build containers using established best practices. If you don’t already have a Snyk account, it’s free to sign up and use Snyk to scan container images and open source dependencies. 

The Docker compatibility layer in Podman provides an easy pathway to transition to using Podman without changing existing workflows and integrations. As Podman grows in popularity, it would be great to see Snyk integration with the native Podman API, but for now these compatibility functions make it super easy to integrate Podman with Snyk.


執筆者紹介

Matt Jarvis is a Senior Developer Advocate at Snyk. He has spent more than 15 years building products and services around open source software, on everything from embedded devices to large scale distributed systems. Most recently he has been focused on the open cloud infrastructure space, and in emerging patterns for cloud native applications. Jarvis is a regular speaker at conferences and meetups across the world, including MesosCon, FOSDEM, Open Infrastructure Summit and All Things Open, and in his spare time runs several UK Cloud Native meetups.

Read full bio