Skip to content

Commit

Permalink
Support OIDC-based SSO on keystone/horizon (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianunruh authored Jul 1, 2024
1 parent 49789e8 commit c74986f
Show file tree
Hide file tree
Showing 24 changed files with 613 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/preview-capi-setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
run: |
echo "::add-mask::${{ secrets.PREVIEW_KUBECONFIG }}"
echo "::add-mask::${{ secrets.GCLOUD_SVC_ACCOUNT_KEY_JSON }}"
echo "::add-mask::${{ secrets.GITLAB_TOKEN }}"
- name: Auth with Google Cloud
uses: google-github-actions/auth@v2
Expand Down Expand Up @@ -63,6 +64,7 @@ jobs:
PREVIEW_KUBECONFIG: ${{ secrets.PREVIEW_KUBECONFIG }}
GCLOUD_SVC_ACCOUNT_KEY_JSON: ${{ secrets.GCLOUD_SVC_ACCOUNT_KEY_JSON }}
GITHUB_TOKEN: ${{ secrets.GH_TOKEN_READ }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}

- name: Post comment to PR
uses: marocchino/sticky-pull-request-comment@v2
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/preview-capi-teardown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
run: |
echo "::add-mask::${{ secrets.PREVIEW_KUBECONFIG }}"
echo "::add-mask::${{ secrets.GCLOUD_SVC_ACCOUNT_KEY_JSON }}"
echo "::add-mask::${{ secrets.GITLAB_TOKEN }}"
- name: Auth with Google Cloud
uses: google-github-actions/auth@v2
Expand Down Expand Up @@ -56,3 +57,4 @@ jobs:
run: ./teardown.sh
env:
PREVIEW_KUBECONFIG: ${{ secrets.PREVIEW_KUBECONFIG }}
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
23 changes: 23 additions & 0 deletions api/v1beta1/horizon_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ type HorizonSpec struct {
// +optional
Server HorizonServerSpec `json:"server,omitempty"`

// +optional
SSO HorizonSSOSpec `json:"sso,omitempty"`

// +optional
Cache CacheSpec `json:"cache,omitempty"`
}
Expand All @@ -51,6 +54,26 @@ type HorizonServerSpec struct {
Resources corev1.ResourceRequirements `json:"resources,omitempty"`
}

type HorizonSSOSpec struct {
// +optional
Enabled bool `json:"enabled,omitempty"`

// +optional
KeystoneURL string `json:"keystoneURL,omitempty"`

// +optional
Methods []HorizonSSOMethod `json:"methods,omitempty"`
}

type HorizonSSOMethod struct {
Kind string `json:"kind"`

Title string `json:"title"`

// +optional
Default bool `json:"default,omitempty"`
}

// HorizonStatus defines the observed state of Horizon
type HorizonStatus struct {
Conditions []metav1.Condition `json:"conditions"`
Expand Down
32 changes: 32 additions & 0 deletions api/v1beta1/keystone_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type KeystoneSpec struct {
// +optional
Notifications KeystoneNotificationsSpec `json:"notifications,omitempty"`

// +optional
OIDC KeystoneOIDCSpec `json:"oidc,omitempty"`

// +optional
ExtraConfig ExtraConfig `json:"extraConfig,omitempty"`
}
Expand All @@ -74,6 +77,35 @@ type KeystoneNotificationsSpec struct {
Enabled bool `json:"enabled,omitempty"`
}

type KeystoneOIDCSpec struct {
// +optional
Enabled bool `json:"enabled,omitempty"`

// +optional
Secret string `json:"secret,omitempty"`

// +optional
IdentityProvider string `json:"identityProvider,omitempty"`

// +optional
DashboardURL string `json:"dashboardURL,omitempty"`

// +optional
ProviderMetadataURL string `json:"providerMetadataURL,omitempty"`

// +optional
RedirectURI string `json:"redirectURI,omitempty"`

// +optional
Scopes []string `json:"scopes,omitempty"`

// +optional
RequireClaims []string `json:"requireClaims,omitempty"`

// +optional
ExtraConfig map[string]string `json:"extraConfig,omitempty"`
}

// KeystoneStatus defines the observed state of Keystone
type KeystoneStatus struct {
Conditions []metav1.Condition `json:"conditions"`
Expand Down
9 changes: 9 additions & 0 deletions api/v1beta1/keystone_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ func (r *Keystone) Default() {
r.Spec.Cache = cacheDefault(r.Spec.Cache)
r.Spec.Database = databaseDefault(r.Spec.Database, r.Name)
r.Spec.API.Image = imageDefault(r.Spec.API.Image, DefaultKeystoneAPIImage)

if r.Spec.OIDC.Enabled {
if len(r.Spec.OIDC.Scopes) == 0 {
r.Spec.OIDC.Scopes = []string{"openid", "email", "profile"}
}
if r.Spec.OIDC.Secret == "" {
r.Spec.OIDC.Secret = "keystone-oidc"
}
}
}

// TODO(user): change verbs to "verbs=create;update;delete" if you want to enable deletion validation.
Expand Down
69 changes: 69 additions & 0 deletions api/v1beta1/zz_generated.deepcopy.go

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

16 changes: 15 additions & 1 deletion ci/preview/capi/controlplane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,21 @@ spec:
vcpus: 4
disk: 60
isPublic: true
horizon: {}
keystone:
oidc:
enabled: true
identityProvider: gitlab
providerMetadataURL: https://gitlab.kcloud.io/.well-known/openid-configuration
extraConfig:
OIDCRemoteUserClaim: preferred_username@
horizon:
sso:
methods:
- kind: openid
title: GitLab
default: true
- kind: credentials
title: Keystone
heat: {}
barbican: {}
magnum: {}
Expand Down
14 changes: 14 additions & 0 deletions ci/preview/capi/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,19 @@ fi
log "Waiting for openstack-operator to become ready"
kubectl -n openstack-system rollout status deploy openstack-operator-controller-manager

log "Ensuring OIDC set up"
if ! kubectl get secret keystone-oidc; then
oidc_redirect_uri=https://keystone.$CLUSTER_DOMAIN/v3/OS-FEDERATION/identity_providers/gitlab/protocols/openid/auth

gitlab_app=$(curl -s -H "PRIVATE-TOKEN: $GITLAB_TOKEN" \
-d "name=$CLUSTER_NAME&redirect_uri=$oidc_redirect_uri&scopes=read_user openid profile email" \
"https://gitlab.kcloud.io/api/v4/applications")

kubectl create secret generic keystone-oidc \
--from-literal=KEYSTONE_OIDC_CLIENT_ID=$(echo $gitlab_app | yq -r '.application_id') \
--from-literal=KEYSTONE_OIDC_CLIENT_SECRET=$(echo $gitlab_app | yq -r '.secret') \
--from-literal=KEYSTONE_OIDC_CRYPTO_PASSPHRASE=$(python -c 'import secrets; print(secrets.token_hex(24))')
fi

log "Applying OpenStack control plane manifests"
sed "s/\$(CLUSTER_DOMAIN)/$CLUSTER_DOMAIN/" controlplane.yaml | kubectl apply -f-
6 changes: 6 additions & 0 deletions ci/preview/capi/teardown.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ log "Cleaning up ingress wildcard DNS record"
if gcloud dns record-sets describe "*.$CLUSTER_DOMAIN" --type=A --zone=$DNS_ZONE; then
gcloud dns record-sets delete "*.$CLUSTER_DOMAIN" --type=A --zone=$DNS_ZONE
fi

log "Cleaning up OAuth apps"
for app_id in $(curl -s -H "PRIVATE-TOKEN: $GITLAB_TOKEN" https://gitlab.kcloud.io/api/v4/applications | yq -r ".[]|select(.application_name==\"$CLUSTER_NAME\").application_id"); do
log "Deleting OAuth app $app_id"
curl -s -H "PRIVATE-TOKEN: $GITLAB_TOKEN" -XDELETE https://gitlab.kcloud.io/api/v4/applications/$app_id
done
48 changes: 48 additions & 0 deletions config/crd/bases/openstack.ospk8s.com_controlplanes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2463,6 +2463,27 @@ spec:
type: object
type: object
type: object
sso:
properties:
enabled:
type: boolean
keystoneURL:
type: string
methods:
items:
properties:
default:
type: boolean
kind:
type: string
title:
type: string
required:
- kind
- title
type: object
type: array
type: object
type: object
ingress:
properties:
Expand Down Expand Up @@ -2914,6 +2935,33 @@ spec:
enabled:
type: boolean
type: object
oidc:
properties:
dashboardURL:
type: string
enabled:
type: boolean
extraConfig:
additionalProperties:
type: string
type: object
identityProvider:
type: string
providerMetadataURL:
type: string
redirectURI:
type: string
requireClaims:
items:
type: string
type: array
scopes:
items:
type: string
type: array
secret:
type: string
type: object
type: object
magnum:
description: MagnumSpec defines the desired state of Magnum
Expand Down
21 changes: 21 additions & 0 deletions config/crd/bases/openstack.ospk8s.com_horizons.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@ spec:
type: object
type: object
type: object
sso:
properties:
enabled:
type: boolean
keystoneURL:
type: string
methods:
items:
properties:
default:
type: boolean
kind:
type: string
title:
type: string
required:
- kind
- title
type: object
type: array
type: object
type: object
status:
description: HorizonStatus defines the observed state of Horizon
Expand Down
Loading

0 comments on commit c74986f

Please sign in to comment.