README
¶
Template repo for php docker services
Setup new project
- Copy this entire project into your new project directory (or copy the template github repo)
- In
/testinitialise the go module (written for go 1.13)go mod init github.com/youruser/yourprojectand check the tests work as-isgo test -v - Replace everywhere that says
php-service(indocker-compose.yaml,Dockerfile,scripts/create-production-docker-compose.sh) with the name of your project - Put your code in src/ directory (replace the index.php and loggedout.php files there already)
- Edit the SSM_PREFIX env var in /scripts/create-production-docker-compose.sh
- Put an sql, or sql.gz file in
/config/db-seeds/seeds.sql.gzwhich has the seeds for your db test data (incl. structure) - If you are going to use OpenID Connect authentication you should edit
config/docker/entrypoint.shand change the LocationMatch setting in the openid config to match whatever file you want to present to users when they logout. (or just updatesrc/loggedout.phpwith your content).
What you get
- Inside the docker container
- Hardened PHP service running php 5.6 and configured for a UTC timezone (edit
/config/docker/date.timezone.iniif you wish to have a different server timezone) running with apache - You can choose to have no auth (don't set HTPASSWD_FILE env var, or OPENID_ENABLED env vars), but you can also enable HTTP Basic Auth by providing an htpasswd file in the HTPASSWD_FILE env var, or openid connect by setting the env var OPENID_ENABLED=true. If you do this you will need to provide aditional configuration. See OpenID Connect authentication.
- A /secrets directory, outside the apache web directory, accessible by your code to store things like database config etc (add more things as you wish in the Dockerfile)
- A script
/config/docker/entrypoint.shwhich does the following:- Loads some SSM params (see below) and puts them into a config file inside the container
/secrets/config.phpwhich has the following things set:- $_CONF['db_name'] set to env var DB_NAME
- $_CONF['db_host'] set to env var DB_HOST
- $_CONF['db_user'] set to env var DB_USER
- $_CONF['db_pass'] set to env var DB_PASS
- $_CONF['sslmode'] set to env var SSLMODE
- $_CONF['sslrootcert'] set to env var SSLROOTCERT
- Creates an htpasswd file in /secrets/htpasswd from the HTPASSWD_FILE env var, and enables basic auth if the HTPASSWD_FILE env var is set.
- Creates an apache config for openid connect auth (using mod_auth_openidc) if the OPENID_ENABLED env var is set to "true". (See later for discussion of other variables which need to be set for this to work).
- Makes a /sessions directory which php is configured to use for storing session.
- Calls the entrypoint of the php container with whatever command you chose (it defaults to running apache)
- Unsets all the env vars at the end so they can't be seen anymore
- Loads some SSM params (see below) and puts them into a config file inside the container
- The RDS SSL combined ca bundle inside the container at
/secrets/rds-combined-ca-bundle.pemgiving you verified SSL connections to AWS RDS instances
- Hardened PHP service running php 5.6 and configured for a UTC timezone (edit
- Several docker-compose files for difference scenarios. Giving you:
- In all docker-compose files:
- A postgres 9.6.11 dependency for your app with a persistent data volume which is seeded from
/config/db-seeds/*.sql.gz - A default user (testdb), database (testdb), and password for postgres
- Your src/ directory mounted into /var/www/html so it will update live if you change any files while the container is running. This is exposed on port 80 by default (overridable with HTTP_PORT env var).
- A postgres 9.6.11 dependency for your app with a persistent data volume which is seeded from
- In
docker-compose.htpasswd.yaml- Only the same as the common options but 'protected' by a default HTTP Basic Auth configuration with user foo and password bar.
- In
docker-compose.openid.yaml- A keycloak server with some defaults to mean you can locally do openid authentication during testing. (The included default openid user is foo with password bar. The keycloak admin interface is exposed on port 8080 by default (overridable with env var KEYCLOAK_PORT)
- A postgres 9.6.11 dependency for keycloak
- Your local website protected by openid authentication against the local keycloak server. There is a pre-configured user with name foo and password bar.
- In
docker-compose.cognito.example.yaml- An nginx reverse proxy providing a self-signed SSL cert and proxying to your php service (this helps with testing integrations like cognito which require redirecting back to an SSL endpoint), this is exposed on https://10.100.0.4
- Helpful (hopefully) example values for the OpenID configuration needed for cognito. See OpenID Connect authentication for more help configuring this.
- In all docker-compose files:
- A script to generate a docker-compose file (which is gitignored) which will have your production credentials in (loaded from SSM, so you will need to run with a valid AWS_PROFILE)
- A couple of scripts for improting and exporting the keycloak settings (if you change them you can persist them
by running the
scripts/keycloak-export.shscript, this will updateconfig/keycloak/local_realm.jsonwith your changes. - An example docker-compose
docker-compose.cognito.example.yamlfile for doing local development against a cognito user pool - Terratest tests which will
- Build and launch the docker file
- Run a validations to check for hardening, htpasswd basic auth, openid auth, and that index.php can be retrieved.
- Are written with stages (which can be individually skipped by setting env vars SKIP_<stage>,
e.g. SKIP_build=true):
- build (docker-compose build)
- launch (docker-compose up
- verify (run the tests)
- destroy (docker-compose down (will also remove the postgres volume used in the tests))
OpenID Connect authentication
This has been tested against AWS Cognito with openid enabled (see Robert Broekelmanns post on medium for the guide I followed to learn about setting up Cognito user pools and app clients).
To enable OpenID auth you need to set the following env vars:
| Env var | Value | Notes |
|---|---|---|
| OPENID_ENABLED | "true" | Must be the string true |
| OPENID_METADATA_URL | The well known metadata url for your provider | In cognito this is https://cognito-idp.<REGION>.amazonaws.com/<COGNITO_USER_POOL_ID>/.well-known/openid-configuration |
| OPENID_CLIENT_ID | The clientid for your client as specified by your open id provider | |
| OPENID_SECRET | The client secret for your clientas specified by your open id provider | |
| OPENID_REDIRECT_URL | The redirect URI which your provider will return the user to in your application | This needs to be set to https://<YOUR_DOMAIN>/redirect_uri to match the apache module configuration |
| OPENID_CRYPTO_PASSPHRASE | The passpharse mod_auth_openidc will use to encrypt secrets | See the mod_auth_openidc config file for more info |
| OPENID_END_SESSION_ENDPOINT | The logout url for your open id provider | Some providers (looking at you AWS Cognito) do not provide this from the metadata endpoint, for any provider that doesn't you will need to set this explicitly. |
Special notes about OPENID_END_SESSION_ENDPOINT
Note: In the following the logout_uri parameter in the OPENID_END_SESSION_ENDPOINT, the logout parameter in the logout link on your site, and the "Sign out URL(s)" in the AWS Cognito "App Client Settings" are all identical.
For AWS Cognito the OPENID_END_SESSION_ENDPOINT env var should be:
https://<AMAZON_COGNITO_DOMAIN>/logout?client_id=<APP_CLIENT_ID>&logout_uri=<SIGN_OUT_URL_AS_SET_IN_COGNITO_APP_CLIENT_SETTINGS>
The logout_uri parameter needs to be a page in your site, which is not protected by openid connect (this is defaulted to src/loggedout.php in our config).
In your app a logout link needs to be of this format:
https://<YOUR_DOMAIN>/redirect_uri?logout=https%3A%2F%2F127.0.0.1%2Floggedout.php
Note: The logout parameter has to be IDENITICAL (but URI encoded!) to the "Sign out URL(s)" you specified in the AWS Cognito "App Client Settings"
Requirements
To build the project
- go 1.13+ (for the tests)
- docker-compose (any version which supports compose templates 3+, written and tested with 1.25)
To run the docker container without the docker-compose file
- Env vars:
- DB_HOST: Host name of the postgres instance to connect to
- DB_NAME: Name of the database inside the postgres host
- DB_USER: Username to auth for postgres
- DB_PASS: Password to auth for postgres
- SSLMODE: PHP postgres SSL mode (verify-full suggested for production)
- SSLROOTCERT: The path to the SSL cert for verifying the SSL connection to the server (for AWS RDS (which is
included in the docker container for you) set this to
/secrets/rds-combined-ca-bundle.pem) - To optionally enable auth either:
- HTPASSWD_FILE: The content to put into the htpasswd file
- OPENID_ENABLED=true - See OpenID Connect authentication