This is the API component to the Secure Image application suite. Secure Image is designed to provide a simple yet secure way for people to take sensitive photographs (or image related documentation) and store it outside of the device's camera roll. It also provides a convenient way to extract the images by providing a secure URL to download an album.
This component builds using GitHub Actions in combination with the OpenShift Container Platform (OCP). The GitHub Actions workflow will build and test the project against various node versions and, once successful, if the changes are on the master
branch trigger an OCP image build using a service account with highly restricted access.
There are two steps for setting up the CICD pipeline:
- Setup a OCP service account with restricted access and add the credentials to GitHub;
- Setup the OCP image build.
To setup the CICD pipeline GitHub needs to be able to trigger an image build in OCP. We do this by setting up a service account that only has access to trigger and image build.
In the root directory of the repo there is an directory containing common OpenShift templates. Use the following command to create a CICD service account for GitHub.
oc process -f ../openshift/templates/cicd.yaml \
-p NAMESPACE=$(oc project --short) | \
oc apply -f -
Parameter | Optional | Description |
---|---|---|
NAMESPACE | NO | The namespace used for all components of the credentials. |
You'll see some output from the above command similar to this:
serviceaccount/github-cicd created
role.authorization.openshift.io/github-cicd created
rolebinding.authorization.openshift.io/github-cicd created
You can list your secrets with the following command:
oc get secrets
Again, you'll see output similar to this:
NAME TYPE DATA AGE
github-cicd-dockercfg-gsd7b kubernetes.io/dockercfg 1 85s
github-cicd-token-9jnw6 kubernetes.io/service-account-token 4 85s
github-cicd-token-gr9pf kubernetes.io/service-account-token 4 85s
Pick either of the secrets beginning with github-cicd-token
and get the token
field from it. You can do this via the Web UI or with the following command providing you have jq
installed:
oc get secret/github-cicd-token-9jnw6 -o json | \
jq '.data.token' | \
tr -d "\""
Pro Tip 🤓: If you have a mac, add | pbcopy
after the above command to copy the token directly to your clipboard.
Once you have your token go to the Settings of your GitHub repo and create the following encrypted secrets:
Name | Optional | Value |
---|---|---|
OPENSHIFTTOKEN | NO | The token from from the command above. |
OPENSHIFTSERVERURL | NO | The URL for the OpenShift console (everything up to the port number). |
These secrets are used by the official RedHat GitHub actions to trigger the image build. You can see them in the workflow file here and in the excerpt below:
steps:
- name: S2I Build
uses: redhat-developer/openshift-actions@v1.1
with:
version: "latest"
openshift_server_url: ${{ secrets.OpenShiftServerURL}}
parameters: '{"apitoken": "${{ secrets.OpenShiftToken }}", "acceptUntrustedCerts": "true"}'
cmd: |
'version'
'start-build secure-image-api-master-build --follow -n devex-mpf-secure-tools'
The second and final step is to setup the image build on the OCP platform. The workflow is setup to only run this step when changes impact the master
branch.
Use the following command to setup the image BuildConfig
in your tools namespace:
oc process -f openshift/templates/build.yaml | oc apply -f -
You can trigger this build manually to check that it works as expected:
oc start-build bc/secure-image-api-master-build --follow
Whereas image is generated by build, all other artifacts are managed using Helm. To deploy the artifacts to various OpenShift environments,
-
install oc and helm cli
-
login to oc by running
oc login ...
-
set environment by running
oc project ...
-
create a yaml values file under helm folder for each environment containing the environment specific and potentially sensitive information. The file must have extension .local.yaml to avoid checking into SCM. For example, for OCP4 dev environment, the file can be named values.ocp4.ev.local.yaml and should contain following information (sensitive data are masked)
minio: accessKey: "xxxxx" secretKey: "xxxxx" route: host: dev-secure-image.apps.silver.devops.gov.bc.ca sessionSecret: "xxxxx" sso: clientSecret: "xxxxx" congJson: | { "temporaryUploadPath": "uploads", "archiveFileBaseName": "IMG_", "templates": { "path": "templates" }, "albumExpirationInDays": 90, "minio": { "bucket": "secure-image-pr", "port": 9000, "secure": false, "expiry": 604800, "region": "us-east-1" }, "session": { "maxAge": 604800000, "expires": 604800000, "domain": ".gov.bc.ca", "memcached": { "hosts": "{{ include "secure-image-api.fullname" . }}-memcached:11211" } }, "sso": { "clientId": "secure-image-api", "callback": "/v1/auth/callback", "authUrl": "https://dev.oidc.gov.bc.ca/auth/realms/secimg/protocol/openid-connect/auth", "tokenUrl": "https://dev.oidc.gov.bc.ca/auth/realms/secimg/protocol/openid-connect/token", "certsUrl": "https://dev.oidc.gov.bc.ca/auth/realms/secimg/protocol/openid-connect/certs" } }
This file overwrites and supplements helm/values.yaml. Consult helm/values.yaml for other values that you want to overwrite by environment.
-
to install artifacts to say dev env, run
helm install secure-image-api -f helm/values.ocp4.dev.local.yaml helm
to upgrade/update, run
helm upgrade secure-image-api helm -f helm/values.ocp4.dev.local.yaml
to ininstall, run
helm uninstall secure-image-api
secure-image-api in above commands is the release name and came be named differently.
Pro Tip 🤓: append
--dry-run
to above commands to preview the effects without applying.
Local development for this component is made easy by using the included docker-compose file. This will start a local server that can be used for development on any of the components.
Create a local directory within the api
sub-folder that the minio container will use to store data. When an album is uploaded it will appear in this directory.
mkdir minio_data
Create a .env
file in the api
sub-folder with the entries show below. See src/config/index.js
and docker-compose.yaml
to understand how they are consumed by the application:
NODE_ENV=development
# Local Docker
MINIO_ACCESS_KEY="xxxx"
MINIO_SECRET_KEY="yyyy"
SSO_CLIENT_SECRET="zzzz"
SESSION_SECRET="aaa"
APP_URL=https://f9d9fbb72386.ngrok.io
Name | Optional | Value |
---|---|---|
MINIO_ACCESS_KEY | NO | The minio access key (line username) |
MINIO_SECRET_KEY | NO | The minio secret key (like password) |
SSO_CLIENT_SECRET | NO | This comes from the client in the SSO Web UI |
SESSION_SECRET | NO | Used to secure HTTP sessions |
APP_URL | NO | The application (API) endpoint |
Pro Tip 🤓:
- Use
openssl rand -hex 6
to generate MINIO_ACCESS_KEY, MINIO_SECRET_KEY, and SESSION_SECRET. - iOS prefers SSL due to AST. You an use
npx ngrok http 8080
to setup a local proxy that will provide an external URL providing bothhttp
andhttps
protocols. - Make sure the URL is registered in your SSO realm as a valid callback URL.
Now, bring up the docker stack / images using docker-compose
:
docker-compose up
At this point your docker stack will be running. See the ProTip above about using ngrok
as a proxy. The external URLs provided by this application can be given used for APP_URL
as well as provided to the iOS and Android applications for local development work.