Kategorien
Wochenbericht

Wochenbericht 2021.21

  1. Stop making your paying customers hunt for the Sign In button on your website.
  2. MDN is launching MDN Plus
  3. Freenode, The Mainstream IRC Network, Is Collapsing
  4. DOOM Captcha – Captchas don’t have to be boring
  5. Youki, a container runtime in Rust, passed all the default tests provided by opencontainers.
  6. 18 Cards of how to design web forms
  7. State Management: How to tell a bad boolean from a good boolean
  8. NocoDB: Freie Airtable-Alternative für No-Code-Datenbankanwendungen

Was zum Lachen: Observer

Kategorien
Wochenbericht

Wochenbericht 2020.44

  1. Complete Docker Course (~3 Hours, Free)
  2. Falsehoods programmers believe about Time Zones
  3. Complete CSS grid tutorial (with color coded diagrams)
  4. Someone replaced the Github DMCA repo with youtube-dl, literally
  5. The Evolution of Version Control System (VCS) Internals

Was zum Lachen: Get Funded

Kategorien
Wochenbericht

Wochenbericht 2020.40

  1. How One Guy Ruined Hacktoberfest 2020
  2. Gitter wird Mitglied der Matrix Community
  3. Windows XP source code leak
  4. A Gentle Introduction to Using a Docker Container as a Dev Environment
  5. Elsa is a minimal, fast and secure runtime for Javascript and Typescript written in Go.

Was zum Lachen: Another day, another daily

Kategorien
Betriebssystem Code Werkzeuge

PHP, Docker, SELinux

When you try to use the PHP Docker Script from my previous post on a Linux distribution that uses SELinux (like Fedora), you might experience some problems.

Basically the Container will not have access to any of the required volumes like:

  • your project files
  • /etc/passwd
  • /etc/group
  • ~/.cache/composer
  • ~/.config/composer
  • ~/.ssh
  • the SSH agent socket

Is SELinux to blame?

To find out if your permission problems are really caused by SELinux you can temporarily disable access blocking:

sudo setenforce 0

When the files are accessible now, you know it’s SELinux. Make sure you turn on enforcing after you’re done testing:

sudo setenforce 1

The Z-flag

You could try to add the Z flag to the volume mapping but this is not recommended!

With the Z-flag set Docker will change the SELinux context of the files inside that volume (similar to a chcon call).

This might be OK for your project files but is highly discouraged for system files like /etc/passwd.

Detecting the problems

SELinux has a very extensive log at /var/log/audit/audit.log. It will log most of the time to this file when access was denied or granted.

In the case of my Docker container some of the problems did not show up in the audit log. To make sure all problems are logged you can use this command:

sudo semodule --disable_dontaudit --build

-D –disable_dontaudit
Temporarily remove dontaudits from policy. Reverts whenever policy is rebuilt

semodule man page

Analyse the log

The log entries you are interested in look like this:

type=AVC msg=audit(1573154170.047:519): avc: denied { read } for pid=37461 comm=„bash“ name=„passwd“ dev=„dm-1“ ino=1879487 scontext=system_u:system_r:container_t:s0:c61,c1013 tcontext=system_u:object_r:passwd_file_t:s0 tclass=file permissive=0

Excerpt from the audit.log

Important here are these parts:

  • the request was denied
  • scontext contains container_t
  • a request was made to a file Composer needs to access

audit2allow to the rescue!

Now we can start fixing the problems using audit2allow.

This tool analyses all failed entries of the SELinux audit log and generates a configuration that allows them.

First you copy all related audit log lines into a new file (let’s call it allow.log).

After that you pass the contents of the file to audit2allow and let it build a module:

cat allow.log | audit2allow -M containermods

Finally you need to load active the build module.

sudo semodule -i containermods.pp

This change is permanent and will survive reboots.

And repeat and repeat and…

You will most likely have to repeat the steps described above multiple times until everything is working smoothly. This means:

  • watch the audit log
  • try running the Composer command
  • append the related denied lines to allow.log
  • call audit2allow and load the module
  • repeat
Kategorien
Allgemein Code Werkzeuge

Running PHP with Docker

As a developer who works on multiple projects you often need different PHP versions for running tests or installing Composer packages.

I created a little Bash script that runs Docker for executing PHP in your project context. The script looks like this (don’t be scared, I will walk you through it step by step):

#!/usr/bin/env bash

phpVersion=7.2
remainingArguments="$@"

if [[ "$1" =~ (5.6|7.0|7.1|7.2|7.3) ]]; then
    phpVersion=$1
    remainingArguments="${@:2}"
fi

echo "Using PHP version $phpVersion"

docker run  --interactive --rm --tty \
    --user $(id -u):$(id -g) \
    -v ${HOME}/.ssh:${HOME}/.ssh:rw \
    -v ${SSH_AUTH_SOCK}:/ssh-auth.sock \
    --env SSH_AUTH_SOCK=/ssh-auth.sock \
    -v /etc/passwd:/etc/passwd:ro \
    -v /etc/passwd:/etc/group:ro \
    -v ${HOME}/.config/composer:${HOME}/.config/composer:rw \
    -v ${HOME}/.cache/composer:${HOME}/.cache/composer:rw \
    --env COMPOSER_CACHE_DIR=${HOME}/.cache/composer \
    --env COMPOSER_HOME=${HOME}/.config/composer \
    -v "$(pwd)":"$(pwd)":rw -w "$(pwd)" \
    --add-host db:127.0.0.1 \
    --net=host \
    intera/docker-ci-php:${phpVersion}-ubuntu \
    php${phpVersion} ${remainingArguments}

The script can be used like this:

php.sh 7.3 vendor/bin/phpunit

The first argument 7.3 is the PHP version. After that you can provide the arguments to the PHP command. The example above would run phpunit with PHP version 7.3.

You can also omit the PHP version argument and it will use the default PHP version that is defined in the script. The following command executes phpunit with PHP 7.2:

php.sh vendor/bin/phpunit

Argument Handling

The first block of the script handles the PHP version switching and extracting the remaining arguments that should be passed on to the PHP command.

By default PHP 7.2 is used and all arguments are passed on:

phpVersion=7.2
remainingArguments="$@"

If the first argument is a known PHP version it overwrites the default version and is removed from the arguments that are passed on:

if [[ "$1" =~ (5.6|7.0|7.1|7.2|7.3) ]]; then
    phpVersion=$1
    remainingArguments="${@:2}"
fi

The docker command parts

Let’s walk though the different parts of the docker command.

The first parameters will start an interactive terminal. Without them you won’t get nicely colored output:

--interactive --tty

The container is removed after the command is finished:

--rm

We switch the user and group to the currently logged on user to prevent permission problems. We also need to mount /etc/passwd and /etc/group. Otherwise the container would not know about the name of the current user and his groups. These volumes can be read-only (:ro).

--user $(id -u):$(id -g) \
-v /etc/passwd:/etc/passwd:ro \
-v /etc/passwd:/etc/group:ro \

The Composer directories from the user’s home directory are mounted to make sure the Composer cache is persisted and it has access to its config:

-v ${HOME}/.config/composer:${HOME}/.config/composer:rw \
-v ${HOME}/.cache/composer:${HOME}/.cache/composer:rw \
--env COMPOSER_CACHE_DIR=${HOME}/.cache/composer \
--env COMPOSER_HOME=${HOME}/.config/composer \

The current directory is mounted as a volume and the working directory of the Docker command is changed to this directory. Without access to your project files executing PHP would not make much sense 😉

Important! Please be aware that all files required by PHP (or Composer) must be subfolders of the current working directory. Symlinks that point outside that folder will not work.

-v "$(pwd)":"$(pwd)":rw -w "$(pwd)" \

The network part

In some of my (TYPO3) projects a Composer script is executed after install / update that needs access to the database (TYPO3 Console).

The database is running in a docker container and its port is mapped to my localhost. This allows me to use the following configuration:

--net=host \
--add-host db:127.0.0.1 \

The net=host option connects the container with the host network which allows it to access the database.

With add-host you can add additional hostname entries. In my case the Docker container running the database is called db which is also used as database hostname in the application config. With the entry above the db host will be resolved to your localhost.

The SSH part

This part is only required when you need SSH authentication. A common use case is loading private Git repositories via Composer.

The .ssh folder is mounted from the user’s home directory. This gives us access to the SSH config, the key files and the known_hosts file. You might be able to change this to a read-only volume when neither of these two conditions apply:

  • not all SSH hosts are present in your known_hosts file and SSH needs to update it
  • you are using a persistent SSH connection (ControlMasterControlPathControlPersist) and its path is located in your ~/.ssh folder

We also forward the socket of your SSH agent to use passwordless authentication:

-v ${HOME}/.ssh:${HOME}/.ssh:rw \
-v ${SSH_AUTH_SOCK}:/ssh-auth.sock \
--env SSH_AUTH_SOCK=/ssh-auth.sock \

The image

The Docker image is custom made and based on Ubuntu and the awesome PPA of Ondřej Surý.

It is publicly available on Docker Hub in PHP version 5.6 to 7.3.

The tag is switched depending on the selected PHP version.

Of course you can use your own image.

intera/docker-ci-php:${phpVersion}-ubuntu \

The PHP command (finally!)

The PHP command is switched based on the selected PHP version.

Finally the arguments passed to the command are forwarded to Composer.

php${phpVersion} ${remainingArguments}

Composer addon

The Docker images described above already contain a Composer executable at /usr/local/bin/composer.phar. This is an example to make use of it:

php.sh /usr/local/bin/composer.phar install

You can make your life even easier when you wrap the command above in another shell script that directly calls Composer:

#!/usr/bin/env bash

THIS_SCRIPT_DIR="$( cd "$( dirname `readlink -f "${BASH_SOURCE[0]}"` )" >/dev/null && pwd )"

phpVersion=7.2
remainingArguments="$@"

if [[ "$1" =~ (5.6|7.0|7.1|7.2|7.3) ]]; then
    phpVersion=$1
    remainingArguments="${@:2}"
fi

${THIS_SCRIPT_DIR}/php.sh ${phpVersion} /usr/local/bin/composer.phar ${remainingArguments}

Now you can just call

composer.sh install

SELinux

There might be issues with Linux distributions using SELinux.

I will publish another article soon that will provide solutions to these problems.