Skip to content

Commit

Permalink
Merge pull request #8 from alan-turing-institute/7-add-docker-image
Browse files Browse the repository at this point in the history
Add docker image
  • Loading branch information
jemrobinson authored Oct 2, 2023
2 parents 6a5eaa0 + 8135427 commit 375f789
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 18 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/publish_docker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
name: Build and publish a Docker image

# Run workflow on pushes to matching branches
on: # yamllint disable-line rule:truthy
push:
branches: ["main"]
tags: ["*"]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-publish-image:
name: Build Docker image and publish to GitHub container repository
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v3

- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v4
with:
images: |
ghcr.io/${{ github.repository }}
- name: Build and publish Docker images
uses: docker/build-push-action@v4
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM python:3.11-alpine

WORKDIR /app

RUN apk add --update --no-cache \
gcc libc-dev libffi-dev

# Upload and install Python package and dependencies
COPY ./apricot apricot
COPY ./pyproject.toml .
COPY ./README.md .
RUN pip install --upgrade hatch pip
# Initialise environment with hatch
RUN hatch run true

# Install executable files and set permissions
COPY ./docker/entrypoint.sh .
COPY ./run.py .
RUN chmod ugo+x ./entrypoint.sh

# Open appropriate ports
EXPOSE 1389

# Run the server
ENTRYPOINT ["./entrypoint.sh"]
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,22 @@ The name is a slightly tortured acronym for: LD**A**P **pr**oxy for Open**I**D *

## Usage

Start the `Apricot` server on port 8080 by running:
Start the `Apricot` server on port 1389 by running:

```bash
python run.py --client-id "<your client ID>" --client-secret "<your client secret>" --backend "<your backend>" --port 8080 --domain "<your domain name>"
python run.py --client-id "<your client ID>" --client-secret "<your client secret>" --backend "<your backend>" --port 1389 --domain "<your domain name>"
```

Alternatively, you can run in Docker by editing `docker/docker-compose.yaml` and running:

```bash
docker-compose up
```

from the `docker` directory.

## Outputs

This will create an LDAP tree that looks like this:

```ldif
Expand Down
16 changes: 16 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
version: "3"
services:
apricot:
container_name: apricot
image: apricot
build: .
environment:
BACKEND: "MicrosoftEntra"
CLIENT_ID: "<your OpenID client ID here"
CLIENT_SECRET: "<your OpenID client secret here>"
DOMAIN: "<your domain here>"
ENTRA_TENANT_ID: "<your Entra tenant ID here>"
ports:
- "1389:1389"
restart: always
38 changes: 38 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#! /bin/sh
# shellcheck disable=SC2086
# shellcheck disable=SC2089

if [ -z "${BACKEND}" ]; then
echo "BACKEND environment variable is not set"
exit 1
fi

if [ -z "${CLIENT_ID}" ]; then
echo "CLIENT_ID environment variable is not set"
exit 1
fi

if [ -z "${CLIENT_SECRET}" ]; then
echo "CLIENT_SECRET environment variable is not set"
exit 1
fi

if [ -z "${DOMAIN}" ]; then
echo "DOMAIN environment variable is not set"
exit 1
fi

# Optional arguments
EXTRA_OPTS=""
if [ -n "${ENTRA_TENANT_ID}" ]; then
EXTRA_OPTS="${EXTRA_OPTS} --entra-tenant-id $ENTRA_TENANT_ID"
fi

# Run the server
hatch run python run.py \
--backend "$BACKEND" \
--client-id "$CLIENT_ID" \
--client-secret "$CLIENT_SECRET" \
--domain "$DOMAIN" \
--port 1389 \
$EXTRA_OPTS
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ classifiers = [
]
dependencies = [
"ldaptor~=21.2.0",
"oauthlib~=3.2.2",
"requests-oauthlib~=1.3.1",
"Twisted~=23.8.0",
"zope.interface~=6.0",
]
Expand Down
39 changes: 23 additions & 16 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
from apricot.oauth import OAuthBackend

if __name__ == "__main__":
parser = argparse.ArgumentParser(
prog="Apricot",
description="Apricot is a proxy for delegating LDAP requests to an OpenID Connect backend.",
)
# Common options needed for all backends
parser.add_argument("-b", "--backend", type=OAuthBackend, help="Which OAuth backend to use.")
parser.add_argument("-d", "--domain", type=str, help="Which domain users belong to.")
parser.add_argument("-p", "--port", type=int, default=8080, help="Port to run on.")
parser.add_argument("-i", "--client-id", type=str, help="OAuth client ID.")
parser.add_argument("-s", "--client-secret", type=str, help="OAuth client secret.")
# Options for Microsoft Entra backend
parser.add_argument("-t", "--entra-tenant-id", type=str, help="Microsoft Entra tenant ID.", required=False)
# Parse arguments
args = parser.parse_args()
try:
parser = argparse.ArgumentParser(
prog="Apricot",
description="Apricot is a proxy for delegating LDAP requests to an OpenID Connect backend.",
)
# Common options needed for all backends
parser.add_argument("-b", "--backend", type=OAuthBackend, help="Which OAuth backend to use.")
parser.add_argument("-d", "--domain", type=str, help="Which domain users belong to.")
parser.add_argument("-p", "--port", type=int, default=1389, help="Port to run on.")
parser.add_argument("-i", "--client-id", type=str, help="OAuth client ID.")
parser.add_argument("-s", "--client-secret", type=str, help="OAuth client secret.")
# Options for Microsoft Entra backend
group = parser.add_argument_group("Microsoft Entra")
group.add_argument("-t", "--entra-tenant-id", type=str, help="Microsoft Entra tenant ID.", required=False)
# Parse arguments
args = parser.parse_args()

# Create the Apricot server
reactor = ApricotServer(**vars(args))
# Create the Apricot server
reactor = ApricotServer(**vars(args))
except Exception:
msg = "Unable to initialise Apricot server from provided command line arguments."
raise ValueError(msg)

# Run the Apricot server
reactor.run()

0 comments on commit 375f789

Please sign in to comment.