Skip to content

Conversation

@JorTurFer
Copy link

@JorTurFer JorTurFer commented Dec 10, 2025

Description

This PR supports incoming Workload Identity Federation flow. New environment variables have been added to allow default configuration:

  • "STACKIT_SERVICE_ACCOUNT_EMAIL" -> Service account email (this isn't new but it was deprecated and deprecation has been removed)
  • "STACKIT_FEDERATED_TOKEN_FILE" -> Directory where the assertion token is placed
  • "STACKIT_IDP_ENDPOINT" -> IDP endpoint to exchange the token
  • "STACKIT_IDP_EXPIRATION_SECONDS" -> Sets token duration. Not used yet but added for SDK downstream proposes.

Except STACKIT_SERVICE_ACCOUNT_EMAIL, all of them have default values (prod values)

This is a new auth method that will be publicly shipped during next weeks

Checklist

  • No generated code was adjusted manually (check comments in file header)
  • Changelogs
    • Changelog in the root directory was adjusted (see here)
    • Changelog(s) of the service(s) were adjusted (see e.g. here)
  • VERSION file(s) of the service(s) were adjusted
  • Code format was applied: make fmt
  • Examples were added / adjusted (see examples/ directory)
  • Unit tests got implemented or updated
  • Unit tests are passing: make test (will be checked by CI)
  • No linter issues: make lint (will be checked by CI)

@JorTurFer JorTurFer requested a review from a team as a code owner December 10, 2025 11:02
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Comment on lines 75 to 94
// Create a new API client, that will authenticate using the wif flow
// You need to create a service account key and configure the federate identity provider,
// then you can init the SDK using default env var
os.Setenv("STACKIT_SERVICE_ACCOUNT_EMAIL", "my-sa@sa-stackit.cloud")
os.Setenv("STACKIT_FEDERATED_TOKEN_FILE", "/path/to/your/federated/token") // Default "/var/run/secrets/stackit.cloud/serviceaccount/token"
os.Setenv("STACKIT_IDP_ENDPOINT", "custom token endpoint") // Default "https://accounts.stackit.cloud/oauth/v2/token"
dnsClient, err = dns.NewAPIClient()
if err != nil {
fmt.Fprintf(os.Stderr, "[DNS API] Creating API client: %v\n", err)
os.Exit(1)
}

// Check that you can make an authenticated request
getZoneResp, err = dnsClient.ListZones(context.Background(), projectId).Execute()

if err != nil {
fmt.Fprintf(os.Stderr, "[DNS API] Error when calling `ZoneApi.GetZones`: %v\n", err)
} else {
fmt.Printf("[DNS API] Number of zones: %v\n", len(*getZoneResp.Zones))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's enough to showcase only an example, where workflow identity is explicit set via config and not via envs. Please extend our README, to make our customer aware of this authentication option. There you can document the env option as well

stackit-sdk-go/README.md

Lines 100 to 222 in 9af03bf

## Authentication
To authenticate with the SDK, you need a [service account](https://docs.stackit.cloud/stackit/en/service-accounts-134415819.html) with appropriate permissions (e.g., `project.owner`, see [here](https://docs.stackit.cloud/stackit/en/assign-permissions-to-a-service-account-134415855.html)). You can create a service account through the STACKIT Portal.
### Authentication Methods
The SDK supports two authentication methods:
1. **Key Flow** (Recommended)
- Uses RSA key-pair based authentication
- Provides better security through short-lived tokens
- Supports both STACKIT-generated and custom key pairs
2. **Token Flow**
- Uses long-lived service account tokens
- Simpler but less secure
### Configuration Priority
The SDK searches for credentials in the following order:
1. Explicit configuration in code
2. Environment variables (KEY_PATH for KEY)
3. Credentials file (`$HOME/.stackit/credentials.json`)
For each authentication method, the key flow is attempted first, followed by the token flow.
### Using the Key Flow
1. Create a service account key in the STACKIT Portal:
- Navigate to `Service Accounts` → Select account → `Service Account Keys` → Create key
- You can either let STACKIT generate the key pair or provide your own RSA key pair (see [Creating an RSA key-pair](https://docs.stackit.cloud/stackit/en/usage-of-the-service-account-keys-in-stackit-175112464.html#UsageoftheserviceaccountkeysinSTACKIT-CreatinganRSAkey-pair) for more details)
- **Note**: it's also possible to create the service account key in other ways (see [Tutorials for Service Accounts](https://docs.stackit.cloud/stackit/en/tutorials-for-service-accounts-134415861.html) for more details)
2. Save the service account key JSON:
```json
{
"id": "uuid",
"publicKey": "public key",
"credentials": {
"kid": "string",
"iss": "my-sa@sa.stackit.cloud",
"sub": "uuid",
"aud": "string",
"privateKey": "private key (if STACKIT-generated)"
}
// ... other fields ...
}
```
3. Configure authentication using any of these methods:
**A. Code Configuration**
```go
// Using service account key file
config.WithServiceAccountKeyPath("path/to/sa_key.json")
// Or using key content directly
config.WithServiceAccountKey(keyJSON)
// Optional: For custom key pairs
config.WithPrivateKeyPath("path/to/private.pem")
// Or using private key content directly
config.WithPrivateKey(privateKeyJSON)
```
**B. Environment Variables**
```bash
# Using service account key
STACKIT_SERVICE_ACCOUNT_KEY_PATH=/path/to/sa_key.json
# or
STACKIT_SERVICE_ACCOUNT_KEY=<sa-key-content>
# Optional: For custom key pairs
STACKIT_PRIVATE_KEY_PATH=/path/to/private.pem
# or
STACKIT_PRIVATE_KEY=<private-key-content>
```
**C. Credentials File** (`$HOME/.stackit/credentials.json`)
```json
{
"STACKIT_SERVICE_ACCOUNT_KEY_PATH": "/path/to/sa_key.json",
"STACKIT_PRIVATE_KEY_PATH": "/path/to/private.pem"
}
```
### Using the Token Flow
1. Create an access token in the STACKIT Portal:
- Navigate to `Service Accounts` → Select account → `Access Tokens` → Create token
- **Note**: it's also possible to create the service account access tokens in other ways (see [Tutorials for Service Accounts](https://docs.stackit.cloud/stackit/en/tutorials-for-service-accounts-134415861.html) for more details)
2. Configure authentication using any of these methods:
**A. Code Configuration**
```go
config.WithToken("your-token")
```
**B. Environment Variables**
```bash
STACKIT_SERVICE_ACCOUNT_TOKEN=your-token
```
**C. Credentials File** (`$HOME/.stackit/credentials.json`)
```json
{
"STACKIT_SERVICE_ACCOUNT_TOKEN": "your-token"
}
```
For detailed implementation examples, see the [authentication example](examples/authentication/authentication.go).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm preparing the docs, but I'll add a note like "Unreleased yet" for this flow and this won't be publicly available till January, to clarify that this won't be possible yet. Other option could be removing the examples from current PR and opening another PR just to merge the docs and examples once the flow is in GA, wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to merge this PR, when the Workload Identity Flow is public. Because once this is merged, this will be automatically released in the SDK. This avoid potential confusion, why the SDK has a authentication method, that isn't supported yet. And in case something needs to be changed, we would need to deprecate it and need to wait with the deprecation period.

wifClientAssertionType = "urn:schwarz:params:oauth:client-assertion-type:workload-jwt"
wifGrantType = "client_credentials"
defaultWifTokenEndpoint = "https://accounts.stackit.cloud/oauth/v2/token"
defaultFederatedTokenPath = "/var/run/secrets/stackit.cloud/serviceaccount/token"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a common path? Because for now we have a credentials file which is by default in $HOME/.stackit/credentials.json, but this can be overridden with an env path. I think it would be good, to keep them together, but when this is a common path, then it should be fine as well. Nevertheless, in both cases it should be document in our Readme.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a well-known pattern on kubernetes context. meanwhile $HOME/.stackit/credentials.json is a path based on user dir, /var/run/secrets/.... is a common pattern on kubernetes (where this auth method will be more used I'd say).
Said this, we can update the current path to whatever you prefer because the planned (SKE) webhook that will generate the things on kubernetes will set the env var and for GH/AzureDevOps integrations, this env var needs to be set or config updated.

Personally, I'd keep the current value as it is, but if you prefer to update it, just let me know the valuer that you'd like. Just to clarify, this path is where the external token is mounted by the platform and not where the SDK will store anything or so.

Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Signed-off-by: Jorge Turrado <jorge.turrado@mail.schwarz>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants