Skip to content

Conversation

@h3adex
Copy link
Contributor

@h3adex h3adex commented Nov 21, 2025

Description

Internal Issue: STACKITTPR-353

Checklist

  • Issue was linked above
  • Code format was applied: make fmt
  • Examples were added / adjusted (see examples/ directory)
  • Docs are up-to-date: make generate-docs (will be checked by CI)
  • Unit tests got implemented or updated
  • Acceptance tests got implemented or updated (see e.g. here)
  • Unit tests are passing: make test (will be checked by CI)
  • No linter issues: make lint (will be checked by CI)

@h3adex h3adex requested a review from a team as a code owner November 21, 2025 13:49
@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from 7ffc785 to 23bb334 Compare November 24, 2025 08:51
}

// Type assert to access token functionality
client, ok := rt.(*clients.KeyFlow)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Implementing all the service account key and environment variable logic might not have been the best idea in hindsight. What do you think about leveraging the existing auth.KeyAuth method and type asserting to *client.KeyFlow instead?

Right now, the Go SDK only returns an http.RoundTripper, but since the underlying type is KeyFlow, we could safely assert it and access the full client. This would significantly simplify and clean up the entire resource implementation.

Copy link
Member

Choose a reason for hiding this comment

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

After taking a deeper look at auth.KeyAuth from the SDK: lgtm

Copy link
Member

Choose a reason for hiding this comment

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

But: Could we please have a unit tests which mocks the API call(s) and tests the whole process? To make sure the type assertion doesn't break on future updates of the SDK core module?

It might help to extract the logic for the access token into a seperate func beforehand which might look like this:

func (e *accessTokenEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
	var model ephemeralTokenModel

	resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
	if resp.Diagnostics.HasError() {
		return
	}

	accessToken, err := getAccessToken(ctx, &e.keyAuthConfig)
	if err != nil {
		core.LogAndAddError(ctx, &resp.Diagnostics, "Access token generation failed", err.Error())
		return
	}

	model.AccessToken = types.StringValue(accessToken)
	resp.Diagnostics.Append(resp.Result.Set(ctx, model)...)
}

func getAccessToken(ctx context.Context, keyAuthConfig *config.Configuration) (string, error) {
	rt, err := auth.KeyAuth(keyAuthConfig)
	if err != nil {
		return "", fmt.Errorf("failed to initialize authentication: %v", err)
	}

	// Type assert to access token functionality
	client, ok := rt.(*clients.KeyFlow)
	if !ok {
		return "", fmt.Errorf("internal error: expected *clients.KeyFlow, but received a different implementation of http.RoundTripper")
	}

	// Retrieve the access token
	accessToken, err := client.GetAccessToken()
	if err != nil {
		return "", fmt.Errorf("error obtaining access token: %v", err)
	}

	return accessToken, nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. Just pushed something which goes into that direction.

setStringField(providerConfig.ServiceAccountKeyPath, func(v string) { ephemeralProviderData.ServiceAccountKeyPath = v })
setStringField(providerConfig.PrivateKey, func(v string) { ephemeralProviderData.PrivateKey = v })
setStringField(providerConfig.PrivateKeyPath, func(v string) { ephemeralProviderData.PrivateKeyPath = v })
setStringField(providerConfig.TokenCustomEndpoint, func(v string) { ephemeralProviderData.TokenCustomEndpoint = v })
Copy link
Member

Choose a reason for hiding this comment

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

either you remove the ProviderData type embedding from the EphemeralProviderData because you don't seem to need it or you set the values here. Currently this is pretty useless.

Copy link
Member

Choose a reason for hiding this comment

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

@h3adex this is still not resolved. The following line is missing here:

ephemeralProviderData.ProviderData = providerData

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed.

@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch 8 times, most recently from 14df9c7 to 73eaf2d Compare November 24, 2025 16:07
@h3adex h3adex requested a review from rubenhoenle November 24, 2025 16:27
Copy link
Member

@rubenhoenle rubenhoenle left a comment

Choose a reason for hiding this comment

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

One general question I still have: What happens when the user authenticates via token flow?

provider "stackit" {
  default_region        = "eu01"
  service_account_token = var.service_account_token
}

}

// Type assert to access token functionality
client, ok := rt.(*clients.KeyFlow)
Copy link
Member

Choose a reason for hiding this comment

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

After taking a deeper look at auth.KeyAuth from the SDK: lgtm

}

// Type assert to access token functionality
client, ok := rt.(*clients.KeyFlow)
Copy link
Member

Choose a reason for hiding this comment

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

But: Could we please have a unit tests which mocks the API call(s) and tests the whole process? To make sure the type assertion doesn't break on future updates of the SDK core module?

It might help to extract the logic for the access token into a seperate func beforehand which might look like this:

func (e *accessTokenEphemeralResource) Open(ctx context.Context, req ephemeral.OpenRequest, resp *ephemeral.OpenResponse) {
	var model ephemeralTokenModel

	resp.Diagnostics.Append(req.Config.Get(ctx, &model)...)
	if resp.Diagnostics.HasError() {
		return
	}

	accessToken, err := getAccessToken(ctx, &e.keyAuthConfig)
	if err != nil {
		core.LogAndAddError(ctx, &resp.Diagnostics, "Access token generation failed", err.Error())
		return
	}

	model.AccessToken = types.StringValue(accessToken)
	resp.Diagnostics.Append(resp.Result.Set(ctx, model)...)
}

func getAccessToken(ctx context.Context, keyAuthConfig *config.Configuration) (string, error) {
	rt, err := auth.KeyAuth(keyAuthConfig)
	if err != nil {
		return "", fmt.Errorf("failed to initialize authentication: %v", err)
	}

	// Type assert to access token functionality
	client, ok := rt.(*clients.KeyFlow)
	if !ok {
		return "", fmt.Errorf("internal error: expected *clients.KeyFlow, but received a different implementation of http.RoundTripper")
	}

	// Retrieve the access token
	accessToken, err := client.GetAccessToken()
	if err != nil {
		return "", fmt.Errorf("error obtaining access token: %v", err)
	}

	return accessToken, nil
}

@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from 73eaf2d to 6134249 Compare November 26, 2025 13:39
@h3adex
Copy link
Contributor Author

h3adex commented Nov 26, 2025

One general question I still have: What happens when the user authenticates via token flow?

provider "stackit" {
  default_region        = "eu01"
  service_account_token = var.service_account_token
}

Will look into that tomorrow.

@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch 2 times, most recently from da532bf to f8cbfbc Compare November 27, 2025 07:30
@h3adex
Copy link
Contributor Author

h3adex commented Nov 28, 2025

Error message when you try to generate a access token without a valid config

Screenshot 2025-11-28 at 09 38 16

@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from b50a665 to aebda00 Compare November 28, 2025 08:39
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from 3163216 to fcb84a8 Compare November 28, 2025 09:12
@h3adex h3adex requested a review from rubenhoenle November 28, 2025 09:13
@rubenhoenle
Copy link
Member

Error message when you try to generate a access token without a valid config
Screenshot 2025-11-28 at 09 38 16

For me it must be at least stated in the docs which requirements exist to use this resource: User must use keyflow for authentication. Or am I wrong here?

@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from d354333 to 4171d2c Compare November 28, 2025 15:20
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from 4171d2c to c30f6a0 Compare November 28, 2025 15:22
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
@h3adex
Copy link
Contributor Author

h3adex commented Nov 28, 2025

E2E Tests
Screenshot 2025-11-28 at 16 25 26

Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
@h3adex h3adex force-pushed the feat/add-ephemeral-access-token-resource branch from 6b4f10c to 8522cb4 Compare December 1, 2025 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants