Search code examples
azure-active-directorytemporal-workflow

Need with with authentication in Temporal Cluster


We have an on-prem Temporal cluster with the below configuration for Authentication.

authorization:
  authorizer: default
  claimMapper: default
  permissionsClaimName: roles
  jwtKeyProvider:
    keySourceURIs:
    - https://login.microsoftonline.com/{azure_tenant_id}/discovery/v2.0/keys

It looks like Temporal caches the RSA keys returned from "keySourceURIs".

Since we are using Azure AD as IdP, it rotates the keys in the background without our knowledge and our Workflows fail with an Authentication error "PERMISSION_DENIED: Request unauthorized.".

I want to know if there is any way to make Temporal aware of the key rotation.


Solution

  • There is a refresh interval here in their helm chart that reads from the environment variable TEMPORAL_JWT_KEY_REFRESH.

    authorization:
        jwtKeyProvider:
            keySourceURIs:
                {{- if .Env.TEMPORAL_JWT_KEY_SOURCE1 }}
                - {{ default .Env.TEMPORAL_JWT_KEY_SOURCE1 "" }}
                {{- end }}
                {{- if .Env.TEMPORAL_JWT_KEY_SOURCE2 }}
                - {{ default .Env.TEMPORAL_JWT_KEY_SOURCE2 "" }}
                {{- end }}
            refreshInterval: {{ default .Env.TEMPORAL_JWT_KEY_REFRESH "1m" }}
        permissionsClaimName: {{ default .Env.TEMPORAL_JWT_PERMISSIONS_CLAIM "permissions" }}
        authorizer: {{ default .Env.TEMPORAL_AUTH_AUTHORIZER "" }}
        claimMapper: {{ default .Env.TEMPORAL_AUTH_CLAIM_MAPPER "" }}
    

    There is a recent documentation bogpost, that is using it as below

      # JWK containing the public keys used to verify access tokens
      - "TEMPORAL_JWT_KEY_SOURCE1=https://login.microsoftonline.com/{Tenant ID}/discovery/v2.0/keys"
      - "TEMPORAL_JWT_KEY_REFRESH=30m"
    

    While examining the Golang code responsible for managing the configuration:

    func (a *defaultTokenKeyProvider) initialize() {
        a.rsaKeys = make(map[string]*rsa.PublicKey)
        a.ecKeys = make(map[string]*ecdsa.PublicKey)
        if a.config.HasSourceURIsConfigured() {
            err := a.updateKeys()
            if err != nil {
                a.logger.Error("error during initial retrieval of token keys: ", tag.Error(err))
            }
        }
        if a.config.RefreshInterval > 0 {
            a.stop = make(chan bool)
            a.ticker = time.NewTicker(a.config.RefreshInterval)
            go a.timerCallback()
        }
    }
    

    I have concerns about the key no longer being updated. I would recommend opening an issue regarding this matter. Actually I've just opened #5127

    But the callback should periodically refresh the key

    func (a *defaultTokenKeyProvider) timerCallback() {
        for {
            select {
            case <-a.stop:
                return
            case <-a.ticker.C:
            }
            if a.config.HasSourceURIsConfigured() {
                err := a.updateKeys()
                if err != nil {
                    a.logger.Error("error while refreshing token keys: ", tag.Error(err))
                }
            }
        }
    }
    

    Regarding the question about whether the URI

    https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys
    

    will keep working after a key rotation, the answer is supposed to be yes. The purpose of the JWKS endpoint is to provide a set of public keys that can be used to verify the authenticity of tokens. As long as the endpoint continues to provide the current set of keys, Temporal token validation should remain functional, even after key rotation.

    So I will close the above issue as soos as it is confirmed to work as expected.