- Python Flask server authentication
- Constraint
- HTTP Basic Authentication
- Requirements
- Set up authorization in the Lowdefy app
- Protect the Python Flask server routes with HTTP Basic authentication
- Retrieve secrets during test and run
Base time: 1 workday (Max: 2)
.
. +
0-1
We are using HTTP basic authentication for our Python Flask server. This is to prevent any unauthorized persons to access our API endpoints, which are available via a public domain.
The Lowdefy Secrets object is an object that can be used to securely store sensitive information. Secrets can be accessed using the _secret
operator.
The secrets object only exists on the backend server, and therefore the _secret
operator can only be used in connections
and requests
. Secrets can only be set with environment variables.
Secrets created as an environment variable must be prefixed with LOWDEFY_SECRET_
. The remaining part of the key is the name of the variable used within the Lowdefy app.
For example, if the environment variable LOWDEFY_SECRET_API_USERNAME
is set to super
, then API_USERNAME
will return super
.
- Edit the
.env
file in the pathfront/
. Append the following lines:
LOWDEFY_SECRET_API_USERNAME=YOUR_API_USERNAME
LOWDEFY_SECRET_API_PASSWORD=YOUR_API_PASSWORD
- Edit the file
lowdefy.yaml
in the pathfront/
. Insert the following code:
...
connections:
- id: conn_my_api
...
baseURL: https://dev.to/api
auth:
username:
_secret: API_USERNAME
password:
_secret: API_PASSWORD
- Configure your Netlify deployment. Click Site Settings --> Build & deploy.
Under the Environment section, add the environment variables for your Lowdefy app.
- Edit the
main.py
file in the pathapp/
. Modify the source code as follows:
...
from flask_httpauth import HTTPBasicAuth
from werkzeug.security import generate_password_hash, check_password_hash
def create_app():
app = Flask(__name__)
auth = HTTPBasicAuth()
API_USERNAME = os.getenv('LOWDEFY_SECRET_API_USERNAME', '')
API_PASSWORD = os.getenv('LOWDEFY_SECRET_API_PASSWORD', '')
users = {
API_USERNAME: generate_password_hash(API_PASSWORD),
}
@auth.verify_password
def verify_password(username, password):
if username in users:
return check_password_hash(users.get(username), password)
return False
@app.route("/")
@auth.login_required
def root():
...
There are many methods of storing and retrieving secrets. However, in this build we will only be covering the use of environment variables.
We need to ensure that the secrets are set in the environment variables on:
- a Python flask server when testing and running locally
- a Docker container server when testing and running locally
- a Docker container server when testing and running in our CI pipeline
- a Docker container server when testing and running in our production instance
- Edit the
Makefile
file in the pathapp/
. Insert the following code:
Both the make
rules docker_run
and docker_prod
, which are used to run a Docker container locally and in our production instance, respectively, accept an argument --env-file
that specifies the environment variables file.
The make run
rule loads the environment variable file using source
before running the Python Flask app locally.
...
docker_run: docker_build docker_clean
docker run --rm -d -p 8080:8080 --env-file=../front/.env --name=objArchiveso archiveso
docker_prod: docker_stop
docker run --rm -d -p 8080:8080 --env-file=../front/.env --name objArchiveso dennislwm/archiveso:latest
...
run:
set -a && source ../front/.env && set +a && FLASK_ENV=development FLASK_APP=main PYTHONPATH=./:./src/archiveso python3 -m flask run --host=0.0.0.0 --port=8080
- Edit the
docker-compose.yml
file in the pathapp/
. Append the following code:
The docker-compose.yml
file accepts the environment variables from the host, which in our case is the CircleCI pipeline. We have to add these key-value pairs as environment variables in our CircleCI project settings.
...
services:
archiveso:
image: archiveso:latest
environment:
- LOWDEFY_SECRET_API_USERNAME
- LOWDEFY_SECRET_API_PASSWORD
...