Class: PG::AzureWorkloadIdentity::AuthTokenGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/pg/azure_workload_identity/auth_token_generator.rb

Overview

Exchanges a Kubernetes-projected federated identity token (as mounted into pods by AKS Workload Identity) for an Azure AD access token via the OAuth 2.0 client-credentials flow with a JWT bearer client assertion.

Instances are callable via #call, which returns a cached access token while it is still valid (with a refresh threshold applied) and otherwise fetches a new one. Token fetches are guarded by a mutex so concurrent callers share a single in-flight request.

Configuration may be passed explicitly to #initialize or populated from the standard Azure Workload Identity environment variables via AuthTokenGenerator.default.

Constant Summary collapse

IDENTITY_ENDPOINT =
"https://login.microsoftonline.com/%<tenant_id>s/oauth2/v2.0/token"
SCOPE =
"https://ossrdbms-aad.database.windows.net/.default"
GRANT_TYPE =
"client_credentials"
CLIENT_ASSERTION_TYPE =
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identity_endpoint:, client_id:, scope:, grant_type:, client_assertion_type:, federated_token_file:) ⇒ AuthTokenGenerator

Returns a new instance of AuthTokenGenerator.

Parameters:

  • identity_endpoint (String)

    the Azure AD token endpoint.

  • client_id (String)

    the AAD application id.

  • scope (String)

    the requested OAuth scope.

  • grant_type (String)

    the OAuth grant type.

  • client_assertion_type (String)

    the client-assertion type.

  • federated_token_file (String)

    path to the projected federated identity JWT.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 75

def initialize( # rubocop:disable Metrics/ParameterLists
  identity_endpoint:,
  client_id:,
  scope:,
  grant_type:,
  client_assertion_type:,
  federated_token_file:
)
  @identity_endpoint = URI.parse(identity_endpoint)
  @client_id = client_id
  @scope = scope
  @grant_type = grant_type
  @client_assertion_type = client_assertion_type
  @federated_token_file = federated_token_file
  @mutex = Mutex.new
  @token = nil
end

Instance Attribute Details

#client_assertion_typeString (readonly)

Returns the client-assertion type (typically "urn:ietf:params:oauth:client-assertion-type:jwt-bearer").

Returns:

  • (String)

    the client-assertion type (typically "urn:ietf:params:oauth:client-assertion-type:jwt-bearer").



62
63
64
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 62

def client_assertion_type
  @client_assertion_type
end

#client_idString (readonly)

Returns the AAD application/client id.

Returns:

  • (String)

    the AAD application/client id.



51
52
53
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 51

def client_id
  @client_id
end

#federated_token_fileString (readonly)

Returns absolute path to the file containing the Kubernetes-projected federated identity JWT.

Returns:

  • (String)

    absolute path to the file containing the Kubernetes-projected federated identity JWT.



66
67
68
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 66

def federated_token_file
  @federated_token_file
end

#grant_typeString (readonly)

Returns the OAuth grant type (typically "client_credentials").

Returns:

  • (String)

    the OAuth grant type (typically "client_credentials").



58
59
60
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 58

def grant_type
  @grant_type
end

#identity_endpointString (readonly)

Returns the Azure AD token endpoint URL.

Returns:

  • (String)

    the Azure AD token endpoint URL.



48
49
50
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 48

def identity_endpoint
  @identity_endpoint
end

#scopeString (readonly)

Returns the requested OAuth scope.

Returns:

  • (String)

    the requested OAuth scope.



54
55
56
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 54

def scope
  @scope
end

Class Method Details

.defaultAuthTokenGenerator

Builds an PG::AzureWorkloadIdentity::AuthTokenGenerator using the standard Azure Workload Identity environment variables (AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_FEDERATED_TOKEN_FILE) and conventional OAuth defaults.

Returns:



36
37
38
39
40
41
42
43
44
45
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 36

def self.default
  new(
    identity_endpoint: format(IDENTITY_ENDPOINT, tenant_id: ENV.fetch("AZURE_TENANT_ID")),
    client_id: ENV.fetch("AZURE_CLIENT_ID"),
    scope: SCOPE,
    grant_type: GRANT_TYPE,
    client_assertion_type: CLIENT_ASSERTION_TYPE,
    federated_token_file: ENV.fetch("AZURE_FEDERATED_TOKEN_FILE")
  )
end

Instance Method Details

#callString

Returns a currently valid Azure AD access token, fetching a new one from the identity endpoint when the cached token is missing or about to expire. Thread-safe: concurrent callers share a single in-flight fetch.

Returns:

  • (String)

    the bearer access token.

Raises:

  • (Error)

    when the federated token cannot be read, the HTTP request fails, the response is non-2xx, or the response body is not valid JSON / lacks the expected fields.



102
103
104
105
106
107
# File 'lib/pg/azure_workload_identity/auth_token_generator.rb', line 102

def call
  @mutex.synchronize do
    @token = refresh unless @token&.valid?
    @token.access_token
  end
end