Skip to content
Draft
17 changes: 14 additions & 3 deletions api/core/v1beta1/workbench_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ type WorkbenchSecretConfig struct {
}

type WorkbenchSecretIniConfig struct {
Database *WorkbenchDatabaseConfig `json:"database.conf,omitempty"`
OpenidClientSecret *WorkbenchOpenidClientSecret `json:"openid-client-secret,omitempty"`
Databricks map[string]*WorkbenchDatabricksConfig `json:"databricks.conf,omitempty"`
Database *WorkbenchDatabaseConfig `json:"database.conf,omitempty"`
OpenidClientSecret *WorkbenchOpenidClientSecret `json:"openid-client-secret,omitempty"`
Databricks map[string]*WorkbenchDatabricksConfig `json:"databricks.conf,omitempty"`
OAuthClients map[string]*WorkbenchOAuthClientConfig `json:"oauth-clients.conf,omitempty"`
}

func (w *WorkbenchSecretIniConfig) GenerateConfigMap() map[string]string {
Expand Down Expand Up @@ -852,6 +853,16 @@ type WorkbenchDatabaseConfig struct {
Password string `json:"password,omitempty"`
}

type WorkbenchOAuthClientConfig struct {
Name string `json:"name,omitempty"`
ClientId string `json:"client-id,omitempty"`
ClientSecret string `json:"client-secret,omitempty"`
AuthorizationUrl string `json:"authorization-url,omitempty"`
TokenUrl string `json:"token-url,omitempty"`
TokenEndpointAuthMethod string `json:"token-endpoint-auth-method,omitempty"`
Scopes []string `json:"scopes,omitempty"`
}

type WorkbenchVsCodeConfig struct {
Enabled int `json:"enabled,omitempty"`
Exe string `json:"exe,omitempty"`
Expand Down
36 changes: 36 additions & 0 deletions api/core/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions client-go/applyconfiguration/core/v1beta1/workbenchsecretconfig.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions client-go/applyconfiguration/utils.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions config/crd/bases/core.posit.team_workbenches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,27 @@ spec:
type: string
type: object
type: object
oauth-clients.conf:
additionalProperties:
properties:
authorization-url:
type: string
client-id:
type: string
client-secret:
type: string
name:
type: string
scopes:
items:
type: string
type: array
token-endpoint-auth-method:
type: string
token-url:
type: string
type: object
type: object
openid-client-secret:
properties:
client-id:
Expand Down
43 changes: 43 additions & 0 deletions internal/controller/core/workbench.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,33 @@ func (r *WorkbenchReconciler) FetchAndSetClientSecretForAzureDatabricks(ctx cont
return nil
}

func (r *WorkbenchReconciler) FetchAndSetOAuthClientSecrets(ctx context.Context, req ctrl.Request, w *positcov1beta1.Workbench) error {
l := r.GetLogger(ctx)

if w.Spec.SecretConfig.WorkbenchSecretIniConfig.OAuthClients == nil {
return nil
}

for integrationName, config := range w.Spec.SecretConfig.WorkbenchSecretIniConfig.OAuthClients {
if config.ClientId == "" {
l.Info("skipping OAuth integration with no client ID", "integration", integrationName)
continue
}

clientSecretName := fmt.Sprintf("dev-oauth-client-secret-%s", integrationName)

if cs, err := product.FetchSecret(ctx, r, req, w.Spec.Secret.Type, w.Spec.Secret.VaultName, clientSecretName); err != nil {
l.Error(err, "error fetching client secret for OAuth integration", "integration", integrationName)
return err
} else {
config.ClientSecret = cs
l.Info("successfully fetched OAuth client secret", "integration", integrationName)
}
}

return nil
}

func (r *WorkbenchReconciler) ReconcileWorkbench(ctx context.Context, req ctrl.Request, w *positcov1beta1.Workbench) (ctrl.Result, error) {
l := r.GetLogger(ctx).WithValues(
"event", "reconcile-workbench",
Expand Down Expand Up @@ -134,6 +161,12 @@ func (r *WorkbenchReconciler) ReconcileWorkbench(ctx context.Context, req ctrl.R
l.Error(err, "error fetching client secret for databricks azure. Not fatal")
}

// fetch OAuth client secrets
if err := r.FetchAndSetOAuthClientSecrets(ctx, req, w); err != nil {
l.Error(err, "error fetching OAuth client secrets")
return ctrl.Result{}, err
}

// now create the service itself
res, err := r.ensureDeployedService(ctx, req, w)
if err != nil {
Expand Down Expand Up @@ -285,6 +318,16 @@ func (r *WorkbenchReconciler) ensureDeployedService(ctx context.Context, req ctr
kubernetesSecrets[secretName]["dev-chronicle-api-key"] = "dev-chronicle-api-key"
}

// OAuth client secrets
if w.Spec.SecretConfig.WorkbenchSecretIniConfig.OAuthClients != nil {
for integrationName, config := range w.Spec.SecretConfig.WorkbenchSecretIniConfig.OAuthClients {
if config.ClientId != "" {
secretKey := fmt.Sprintf("dev-oauth-client-secret-%s", integrationName)
allSecrets[secretKey] = secretKey
}
}
}

if targetSpc, err := product.GetSecretProviderClassForAllSecrets(
w, w.SecretProviderClassName(),
req.Namespace, w.Spec.Secret.VaultName,
Expand Down
Loading