Add Authentication to Endpoints

Ideally when deploying a Service it is a good idea to protect publically exposed ports using some form of authentication.

Truefoundry provides an easy way to add basic authentication to your port endpoints that do not require any code changes to your application.

πŸ“˜

Advanced Authentication

Other forms of authentication like token or certificate based authentication are on our roadmap. Please reach out to us if you have such a requirement.

Adding Basic authentication to Service

We can add basic (username and password) authentication to a Port of the Service in the Python definition using servicefoundry.BasicAuthCreds (or equivalently in YAML spec under ports.[*].auth section)

Here is an example where we add basic auth to a FastAPI app running on port 8080.

from servicefoundry import Build, Service, Port, BasicAuthCreds, GitSource, DockerFileBuild

svc = Service(
    name="fastapi",
    image=Build(
        build_source=GitSource(
            repo_url="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker",
            branch_name="master",
            ref="01201e19470c1da7618fa9ab361fe7e5d041b147"
        ),
        build_spec=DockerFileBuild(
            dockerfile_path="./docker-images/python3.11-slim.dockerfile",
            build_context_path="./docker-images/"
        )
    ),
    env={"PORT": 8080},
    ports=[
        Port(
            port=8080,
            host="fastapi-my-workspace-8080.truefoundry.my-org.com",
            auth=BasicAuthCreds(
                username="hello",
                password="pass"
            )
        )
    ]
)
type: service
name: fastapi
image:
  type: build
  build_spec:
    type: dockerfile
    dockerfile_path: ./docker-images/python3.11-slim.dockerfile
    build_context_path: ./docker-images/
  build_source:
    type: git
    repo_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
    branch_name: master
    ref: 01201e19470c1da7618fa9ab361fe7e5d041b147
env:
  PORT: '8080'
ports:
  - expose: true
    port: 8080
    protocol: TCP
    app_protocol: http
    host: fastapi-my-workspace-8080.truefoundry.my-org.com
    auth:
      username: hello
      password: pass

The only change we have made is adding theauth argument to Port

Port(
    ...
    auth=BasicAuthCreds(
        username="hello",
        password="pass"
    )
)
ports:
  - ...
    auth:
      username: hello
      password: pass

We can do the same configuration using the UI. Select Custom Security Rule on the port and enter username and password.

Adding auth to the port using UI

Adding auth to the port using UI

🚧

Handling Sensitive Information

Note when you add username and password to your Python definition or YAML file, take care not to hardcode it or commit it to your version control.

There are multiple ways to read the credentials from external sources. For e.g. you can read and pass the password from environment

import os

service = Service(
    ...,
    Port(
        ...
        auth=BasicAuthCreds(
            username=os.environ["PORT_USERNAME"],
            password=os.environ["PORT_PASSWORD"],
        )
    ),
)
export PORT_USERNAME=hello
export PORT_PASSWORD=pass

sfy patch -f servicefoundry.yaml --filter '.ports[0].auth = {"type": "basic_auth", "username": "'"${PORT_USERNAME}"'", "password": "'"${PORT_PASSWORD}"'"}' --output-file servicefoundry-patched.yaml

On deploying the service, now the endpoint will show a padlock :lock: indicating it needs authentication to access

When you try accessing the endpoint from a browser, it should prompt for credentials

Similarly, when using cURL, you'll need to pass the credentials

curl -v -X GET --user hello:pass https://fastapi-my-workspace-8080.truefoundry.my-org.com/