Charmed Temporal K8s How To - Authorization

Authorization

Enabling authorization requires that you have an active Charmed Temporal K8s Operator deployed as described in the tutorial. It is recommended that you first go through the steps of enabling authentication as outlined here.

By default the Temporal Server doesn’t offer any authorization, but it offers the plugin mechanism to add a custom one. We have added an OAuth-based authentication using Google Cloud and an authorization mechanism that leverages Google Cloud and OpenFGA. This custom build of the Temporal Server can be found here.

Deploy OpenFGA

To deploy Charmed OpenFGA K8s, you need to run the following command, which will fetch the charm from Charmhub and deploy it to your model:

juju deploy openfga-k8s --channel edge

Wait until the application is ready - when it is ready, juju status will show:

Model           Controller           Cloud/Region        Version  SLA          Timestamp
temporal-model  temporal-controller  microk8s/localhost  3.1.5    unsupported  12:35:24+03:00

App                 Version   Status    Scale  Charm                Channel    Rev  Address         Exposed  Message
openfga-k8s                   blocked      1   openfga-k8s          edge         9  10.152.183.144  no       installing agent
postgresql-k8s      14.7      active       1   postgresql-k8s       14/stable   73  10.152.183.250  no       Primary
temporal-admin-k8s            active       1   temporal-admin-k8s   stable       4  10.152.183.21   no
temporal-k8s                  active       1   temporal-k8s         stable       9  10.152.183.191  no

Unit                   Workload   Agent  Address      Ports  Message
openfga-k8s/0*         blocked    idle   10.1.232.7          Waiting for postgresql relation
postgresql-k8s/0*      active     idle   10.1.232.66         Primary
temporal-admin-k8s/0*  active     idle   10.1.232.71
temporal-k8s/0*        active     idle   10.1.232.64

Relate OpenFGA K8s to PostgreSQL K8s

To relate the two charms together, run the following command:

juju relate openfga-k8s postgresql-k8s

Wait until the charm has settled - when ready, juju status --relations will show:

Model           Controller           Cloud/Region        Version  SLA          Timestamp
temporal-model  temporal-controller  microk8s/localhost  3.1.5    unsupported  12:35:24+03:00

App                 Version   Status    Scale  Charm                Channel    Rev  Address         Exposed  Message
openfga-k8s                   active       1   openfga-k8s          edge         9  10.152.183.144  no
postgresql-k8s      14.7      active       1   postgresql-k8s       14/stable   73  10.152.183.250  no       Primary
temporal-admin-k8s            active       1   temporal-admin-k8s   stable       4  10.152.183.21   no
temporal-k8s                  active       1   temporal-k8s         stable       9  10.152.183.191  no

Unit                   Workload   Agent  Address      Ports  Message
openfga-k8s/0*         active     idle   10.1.232.7
postgresql-k8s/0*      active     idle   10.1.232.66         Primary
temporal-admin-k8s/0*  active     idle   10.1.232.71
temporal-k8s/0*        active     idle   10.1.232.64

Relation provider                 Requirer                       Interface          Type     Message
openfga-k8s:peer                  openfga-k8s:peer               openfga-peer       peer
postgresql-k8s:database           openfga-k8s:database           postgresql_client  regular
postgresql-k8s:database           temporal-k8s:db                postgresql_client  regular
postgresql-k8s:database           temporal-k8s:visibility        postgresql_client  regular
postgresql-k8s:database-peers     postgresql-k8s:database-peers  postgresql_peers   peer
postgresql-k8s:restart            postgresql-k8s:restart         rolling_op         peer
temporal-admin-k8s:admin          temporal-k8s:admin             temporal           regular
temporal-k8s:peer                 temporal-k8s:peer              temporal           peer

At this point, we have a functioning OpenFGA store which we can now use to store namespace access rules.

Relate Temporal K8s to OpenFGA K8s

To enable authorization, we must first configure the Temporal Server as follows:

juju config temporal-k8s auth-enabled=true

At this point, the temporal-k8s application should be in a blocked state with a message openfga:temporal relation not ready. We can now relate the two charms together by running the following command:

juju relate temporal-k8s openfga-k8s

Once the units settle, the temporal-k8s application should still be in a blocked state, but with an updated message missing openfga authorization model. We can now create an authorization model in the OpenFGA store by running the following command:

juju run temporal-k8s/0 create-authorization-model  model="$(<temporal_auth_model.json)" --string-args=true

Wait until the charm has settled - when ready, juju status --relations will show:

Model           Controller           Cloud/Region        Version  SLA          Timestamp
temporal-model  temporal-controller  microk8s/localhost  3.1.5    unsupported  12:35:24+03:00

App                 Version   Status    Scale  Charm                Channel    Rev  Address         Exposed  Message
openfga-k8s                   active       1   openfga-k8s          edge         9  10.152.183.144  no
postgresql-k8s      14.7      active       1   postgresql-k8s       14/stable   73  10.152.183.250  no       Primary
temporal-admin-k8s            active       1   temporal-admin-k8s   stable       4  10.152.183.21   no
temporal-k8s                  active       1   temporal-k8s         stable       9  10.152.183.191  no

Unit                   Workload   Agent  Address      Ports  Message
openfga-k8s/0*         active     idle   10.1.232.7
postgresql-k8s/0*      active     idle   10.1.232.66         Primary
temporal-admin-k8s/0*  active     idle   10.1.232.71
temporal-k8s/0*        active     idle   10.1.232.64         auth enabled

Relation provider                 Requirer                       Interface          Type     Message
openfga-k8s:openfga               temporal-k8s:openfga           openfga            regular
openfga-k8s:peer                  openfga-k8s:peer               openfga-peer       peer
postgresql-k8s:database           openfga-k8s:database           postgresql_client  regular
postgresql-k8s:database           temporal-k8s:db                postgresql_client  regular
postgresql-k8s:database           temporal-k8s:visibility        postgresql_client  regular
postgresql-k8s:database-peers     postgresql-k8s:database-peers  postgresql_peers   peer
postgresql-k8s:restart            postgresql-k8s:restart         rolling_op         peer
temporal-admin-k8s:admin          temporal-k8s:admin             temporal           regular
temporal-k8s:peer                 temporal-k8s:peer              temporal           peer

At this point, our Temporal Server is active again with authorization enabled. This means that any request made to the Temporal Server will need to be authenticated using Google OAuth.

Create OpenFGA Authorization Rules

Once authorization is enabled, you will not be able to access any namespace in Temporal. You must now create the necessary tuples in the OpenFGA store to enable users read/write access to different namespaces.

The authorization model used is as follows:

model
  schema 1.1

type user
type group
  relations
    define member: [user]
type namespace
  relations
    define admin: [group#member]
    define reader: [group#member] or writer
    define writer: [group#member] or admin

The above model is a simple way of relating users to groups to namespaces. A user can be related to a group as a member, and a group can be related to a namespace as either a reader, writer or admin. For example, if user john is a member of group abc, and group abc is related to namespace example as a writer, then user john will be assigned write access on namespace example.

To add authorization rules to our OpenFGA store, we can use the available actions as follows:

# Add user to group:
juju run temporal-k8s/0 add-auth-rule user="<your_email>" group="test_group"

# Output:
Running operation 19 with 1 task
  - task 20 on unit-temporal-k8s-0

Waiting for task 20...
output: 'operation type "create" for user "<your_email>" on group "test_group" successful'
result: command succeeded

# Assign group 'writer' role to namespace:
juju run temporal-k8s/0 add-auth-rule group="test_group" namespace="default" role="writer"

# Output:
Running operation 19 with 1 task
  - task 20 on unit-temporal-k8s-0

Waiting for task 20...
output: 'operation type "create" for group "test_group" and role "writer" on namespace "default" successful'
result: command succeeded

And you’re done! If the above actions ran successfully, you should be able to access the default namespace in Temporal with the authenticated user identified by <your_email>, whether through web UI login or the use of a Google Cloud service account.

The following actions may also be used for removing auth rules, checking access rules and for auditing purposes:

# 1. Check auth rule
juju run temporal-k8s/0 check-auth-rule user="<your_email>" namespace="default" role="writer"

# Output:
output: "True"
result: command succeeded

# 2. List auth rules
juju run temporal-k8s/0 list-auth-rule user="<your_email>"

# Output:
output: |
  admin: '[]'
  member: '[''group:test_group'']'
  reader: '[''namespace:default'']'
  writer: '[''namespace:default'']'
result: command succeeded

# 3. Remove auth rule
juju run temporal-k8s/0 remove-auth-rule user="<your_email>" group="test_group"

# Output:
output: 'operation type "delete" for user "<your_email>" on group "test_group" successful'
result: command succeeded

Temporal System Admins

A Temporal System Admin refers to anyone who has access to all namespaces, as well as the ability to administer namespace creation and removal. This can be enabled as follows:


# Configure admin group (can be multiple comma-separated groups) and add system admin
juju config temporal-k8s auth-admin-groups="admins"
juju run temporal-k8s/0 add-auth-rule user="<your_email>" group="admins"

# List system admins
juju run temporal-k8s/0 list-system-admins

# Output:
output:
  admins: '[''<your_email>'']'
result: command succeeded

Once configured, the user with <your_email> will be able to see all namespaces through the Web UI as well as create new namespaces using tctl.