-
Notifications
You must be signed in to change notification settings - Fork 24
feat: Support workload identity federation flow #4074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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>
| // 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)) | ||
| } |
There was a problem hiding this comment.
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
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). | |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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>
Description
This PR supports incoming Workload Identity Federation flow. New environment variables have been added to allow default configuration:
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
make fmtexamples/directory)make test(will be checked by CI)make lint(will be checked by CI)