Skip to content

Commit 9df05b3

Browse files
authored
Merge pull request #762 from jetstack/oidc_upload
Upload OIDC discovery data to disco backend
2 parents dfc7c39 + 880b0be commit 9df05b3

File tree

12 files changed

+378
-72
lines changed

12 files changed

+378
-72
lines changed

api/datareading.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func (o *DataReading) UnmarshalJSON(data []byte) error {
6464
target any
6565
assign func(any)
6666
}{
67+
{&OIDCDiscoveryData{}, func(v any) { o.Data = v.(*OIDCDiscoveryData) }},
6768
{&DiscoveryData{}, func(v any) { o.Data = v.(*DiscoveryData) }},
6869
{&DynamicData{}, func(v any) { o.Data = v.(*DynamicData) }},
6970
}

api/datareading_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ func TestDataReading_UnmarshalJSON(t *testing.T) {
7575
}`,
7676
wantDataType: &DynamicData{},
7777
},
78+
{
79+
name: "OIDCDiscoveryData type",
80+
input: `{
81+
"cluster_id": "11111111-2222-3333-4444-555555555555",
82+
"data-gatherer": "oidc",
83+
"timestamp": "2024-06-01T12:00:00Z",
84+
"data": {
85+
"openid_configuration": {"issuer": "https://example.com"},
86+
"jwks": {"keys": []}
87+
},
88+
"schema_version": "v1"
89+
}`,
90+
wantDataType: &OIDCDiscoveryData{},
91+
},
7892
{
7993
name: "Invalid JSON",
8094
input: `not a json`,

deploy/charts/disco-agent/templates/configmap.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ data:
1919
{{- . | toYaml | nindent 6 }}
2020
{{- end }}
2121
data-gatherers:
22+
- kind: oidc
23+
name: ark/oidc
2224
- kind: k8s-discovery
2325
name: ark/discovery
2426
- kind: k8s-dynamic

deploy/charts/disco-agent/tests/__snapshot__/configmap_test.yaml.snap

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ custom-cluster-description:
77
cluster_description: "A cloud hosted Kubernetes cluster hosting production workloads.\n\nteam: team-1\nemail: team-1@example.com\npurpose: Production workloads\n"
88
period: "12h0m0s"
99
data-gatherers:
10+
- kind: oidc
11+
name: ark/oidc
1012
- kind: k8s-discovery
1113
name: ark/discovery
1214
- kind: k8s-dynamic
@@ -114,6 +116,8 @@ custom-cluster-name:
114116
cluster_description: ""
115117
period: "12h0m0s"
116118
data-gatherers:
119+
- kind: oidc
120+
name: ark/oidc
117121
- kind: k8s-discovery
118122
name: ark/discovery
119123
- kind: k8s-dynamic
@@ -221,6 +225,8 @@ custom-period:
221225
cluster_description: ""
222226
period: "1m"
223227
data-gatherers:
228+
- kind: oidc
229+
name: ark/oidc
224230
- kind: k8s-discovery
225231
name: ark/discovery
226232
- kind: k8s-dynamic
@@ -328,6 +334,8 @@ defaults:
328334
cluster_description: ""
329335
period: "12h0m0s"
330336
data-gatherers:
337+
- kind: oidc
338+
name: ark/oidc
331339
- kind: k8s-discovery
332340
name: ark/discovery
333341
- kind: k8s-dynamic

examples/machinehub.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
# go run . agent --one-shot --machine-hub -v 6 --agent-config-file ./examples/machinehub.yaml
1313

1414
data-gatherers:
15+
# Gather Kubernetes OIDC information
16+
- name: ark/oidc
17+
kind: oidc
18+
1519
# Gather Kubernetes API server version information
1620
- name: ark/discovery
1721
kind: k8s-discovery

examples/machinehub/input.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,34 @@
11
[
2+
{
3+
"data-gatherer": "ark/oidc",
4+
"data": {
5+
"openid_configuration": {
6+
"id_token_signing_alg_values_supported": [
7+
"RS256"
8+
],
9+
"issuer": "https://kubernetes.default.svc.cluster.local",
10+
"jwks_uri": "https://10.10.1.2:6443/openid/v1/jwks",
11+
"response_types_supported": [
12+
"id_token"
13+
],
14+
"subject_types_supported": [
15+
"public"
16+
]
17+
},
18+
"jwks": {
19+
"keys": [
20+
{
21+
"alg": "RS256",
22+
"e": "AQAB",
23+
"kid": "C-2916LkMJqepqULK2nqhq6uzVB6So_yyGnqyuor71Q",
24+
"kty": "RSA",
25+
"n": "sYh6rDpl5DyzBk8qlnYXo6Sf9WbplnXJv3tPxWTvhCFsVu9G5oWjknkafVDq5UOJrlybJJNjBmUyiEi1wbdnuhceJS7rZ3sRnNp3aNoS0omCR6iHJCOuoboSlcaPuRmYw4oWXlVUXlKyw8PYPVbNCcTLuq9nqf8y33mIqe7XJsf5-Z5P05WbK9Rzj-SJvlZLQ4dSFtIiwqLkm_2fpRLj0d8Af1F6vuztnhhUE2_PDsfIWdl_kJKkrK3B5x7k5tgTyFrNQPzlRBgK9jmK0HskwAFIDaLKb7FUWuUiQjn94rjKCED4iy201YPAoZBKIHFDlFVkQ_S3quwPcRyOS18r7w",
26+
"use": "sig"
27+
}
28+
]
29+
}
30+
}
31+
},
232
{
333
"data-gatherer": "ark/discovery",
434
"data": {

internal/cyberark/dataupload/dataupload.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ type Snapshot struct {
5757
ClusterDescription string `json:"cluster_description,omitempty"`
5858
// K8SVersion is the version of Kubernetes which the cluster is running.
5959
K8SVersion string `json:"k8s_version"`
60+
// OIDCConfig contains OIDC configuration data from the API server's
61+
// `/.well-known/openid-configuration` endpoint
62+
OIDCConfig map[string]any `json:"openid_configuration,omitempty"`
63+
// OIDCConfigError contains any error encountered while fetching the OIDC configuration
64+
OIDCConfigError string `json:"openid_configuration_error,omitempty"`
65+
// JWKS contains JWKS data from the API server's `/openid/v1/jwks` endpoint
66+
JWKS map[string]any `json:"jwks,omitempty"`
67+
// JWKSError contains any error encountered while fetching the JWKS
68+
JWKSError string `json:"jwks_error,omitempty"`
6069
// Secrets is a list of Secret resources in the cluster. Not all Secret
6170
// types are included and only a subset of the Secret data is included.
6271
Secrets []runtime.Object `json:"secrets"`

pkg/client/client_cyberark.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,25 @@ func baseSnapshotFromOptions(opts Options) dataupload.Snapshot {
104104
}
105105
}
106106

107+
// extractOIDCFromReading converts the opaque data from a OIDCDiscoveryData
108+
// data reading to allow access to the OIDC fields within.
109+
func extractOIDCFromReading(reading *api.DataReading, target *dataupload.Snapshot) error {
110+
if reading == nil {
111+
return fmt.Errorf("programmer mistake: the DataReading must not be nil")
112+
}
113+
data, ok := reading.Data.(*api.OIDCDiscoveryData)
114+
if !ok {
115+
return fmt.Errorf(
116+
"programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. "+
117+
"This DataReading (%s) has data type %T", reading.DataGatherer, reading.Data)
118+
}
119+
target.OIDCConfig = data.OIDCConfig
120+
target.OIDCConfigError = data.OIDCConfigError
121+
target.JWKS = data.JWKS
122+
target.JWKSError = data.JWKSError
123+
return nil
124+
}
125+
107126
// extractClusterIDAndServerVersionFromReading converts the opaque data from a DiscoveryData
108127
// data reading to allow access to the Kubernetes version fields within.
109128
func extractClusterIDAndServerVersionFromReading(reading *api.DataReading, target *dataupload.Snapshot) error {
@@ -161,6 +180,7 @@ func extractResourceListFromReading(reading *api.DataReading, target *[]runtime.
161180
// and populates the relevant field(s) of the Snapshot based on the DataReading's data.
162181
// Deleted resources are excluded from the snapshot because they are not needed by CyberArk.
163182
var defaultExtractorFunctions = map[string]func(*api.DataReading, *dataupload.Snapshot) error{
183+
"ark/oidc": extractOIDCFromReading,
164184
"ark/discovery": extractClusterIDAndServerVersionFromReading,
165185
"ark/secrets": func(r *api.DataReading, s *dataupload.Snapshot) error {
166186
return extractResourceListFromReading(r, &s.Secrets)

pkg/client/client_cyberark_convertdatareadings_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,70 @@ func TestExtractServerVersionFromReading(t *testing.T) {
126126
}
127127
}
128128

129+
// TestExtractOIDCFromReading tests the extractOIDCFromReading function.
130+
func TestExtractOIDCFromReading(t *testing.T) {
131+
type testCase struct {
132+
name string
133+
reading *api.DataReading
134+
expectedSnapshot dataupload.Snapshot
135+
expectError string
136+
}
137+
tests := []testCase{
138+
{
139+
name: "nil reading",
140+
expectError: `programmer mistake: the DataReading must not be nil`,
141+
},
142+
{
143+
name: "nil data",
144+
reading: &api.DataReading{
145+
DataGatherer: "ark/oidc",
146+
Data: nil,
147+
},
148+
expectError: `programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. This DataReading (ark/oidc) has data type <nil>`,
149+
},
150+
{
151+
name: "wrong data type",
152+
reading: &api.DataReading{
153+
DataGatherer: "ark/oidc",
154+
Data: &api.DiscoveryData{},
155+
},
156+
expectError: `programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. This DataReading (ark/oidc) has data type *api.DiscoveryData`,
157+
},
158+
{
159+
name: "happy path",
160+
reading: &api.DataReading{
161+
DataGatherer: "ark/oidc",
162+
Data: &api.OIDCDiscoveryData{
163+
OIDCConfig: map[string]any{"issuer": "https://example.com"},
164+
OIDCConfigError: "oidc-err",
165+
JWKS: map[string]any{"keys": []any{}},
166+
JWKSError: "jwks-err",
167+
},
168+
},
169+
expectedSnapshot: dataupload.Snapshot{
170+
OIDCConfig: map[string]any{"issuer": "https://example.com"},
171+
OIDCConfigError: "oidc-err",
172+
JWKS: map[string]any{"keys": []any{}},
173+
JWKSError: "jwks-err",
174+
},
175+
},
176+
}
177+
178+
for _, test := range tests {
179+
t.Run(test.name, func(t *testing.T) {
180+
var snapshot dataupload.Snapshot
181+
err := extractOIDCFromReading(test.reading, &snapshot)
182+
if test.expectError != "" {
183+
assert.EqualError(t, err, test.expectError)
184+
assert.Equal(t, dataupload.Snapshot{}, snapshot)
185+
return
186+
}
187+
require.NoError(t, err)
188+
assert.Equal(t, test.expectedSnapshot, snapshot)
189+
})
190+
}
191+
}
192+
129193
// TestExtractResourceListFromReading tests the extractResourceListFromReading function.
130194
func TestExtractResourceListFromReading(t *testing.T) {
131195
type testCase struct {

pkg/client/client_cyberark_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ func fakeReadings() []*api.DataReading {
104104
}
105105

106106
return append([]*api.DataReading{
107+
{
108+
DataGatherer: "ark/oidc",
109+
Data: &api.OIDCDiscoveryData{
110+
OIDCConfigError: "Failed to fetch /.well-known/openid-configuration: 404 Not Found",
111+
JWKSError: "Failed to fetch /openid/v1/jwks: 404 Not Found",
112+
},
113+
},
107114
{
108115
DataGatherer: "ark/discovery",
109116
Data: &api.DiscoveryData{

0 commit comments

Comments
 (0)