Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/datareading.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func (o *DataReading) UnmarshalJSON(data []byte) error {
target any
assign func(any)
}{
{&OIDCDiscoveryData{}, func(v any) { o.Data = v.(*OIDCDiscoveryData) }},
{&DiscoveryData{}, func(v any) { o.Data = v.(*DiscoveryData) }},
{&DynamicData{}, func(v any) { o.Data = v.(*DynamicData) }},
}
Expand Down
14 changes: 14 additions & 0 deletions api/datareading_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ func TestDataReading_UnmarshalJSON(t *testing.T) {
}`,
wantDataType: &DynamicData{},
},
{
name: "OIDCDiscoveryData type",
input: `{
"cluster_id": "11111111-2222-3333-4444-555555555555",
"data-gatherer": "oidc",
"timestamp": "2024-06-01T12:00:00Z",
"data": {
"openid_configuration": {"issuer": "https://example.com"},
"jwks": {"keys": []}
},
"schema_version": "v1"
}`,
wantDataType: &OIDCDiscoveryData{},
},
{
name: "Invalid JSON",
input: `not a json`,
Expand Down
2 changes: 2 additions & 0 deletions deploy/charts/disco-agent/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ data:
{{- . | toYaml | nindent 6 }}
{{- end }}
data-gatherers:
- kind: oidc
name: ark/oidc
- kind: k8s-discovery
name: ark/discovery
- kind: k8s-dynamic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ custom-cluster-description:
cluster_description: "A cloud hosted Kubernetes cluster hosting production workloads.\n\nteam: team-1\nemail: [email protected]\npurpose: Production workloads\n"
period: "12h0m0s"
data-gatherers:
- kind: oidc
name: ark/oidc
- kind: k8s-discovery
name: ark/discovery
- kind: k8s-dynamic
Expand Down Expand Up @@ -114,6 +116,8 @@ custom-cluster-name:
cluster_description: ""
period: "12h0m0s"
data-gatherers:
- kind: oidc
name: ark/oidc
- kind: k8s-discovery
name: ark/discovery
- kind: k8s-dynamic
Expand Down Expand Up @@ -221,6 +225,8 @@ custom-period:
cluster_description: ""
period: "1m"
data-gatherers:
- kind: oidc
name: ark/oidc
- kind: k8s-discovery
name: ark/discovery
- kind: k8s-dynamic
Expand Down Expand Up @@ -328,6 +334,8 @@ defaults:
cluster_description: ""
period: "12h0m0s"
data-gatherers:
- kind: oidc
name: ark/oidc
- kind: k8s-discovery
name: ark/discovery
- kind: k8s-dynamic
Expand Down
4 changes: 4 additions & 0 deletions examples/machinehub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
# go run . agent --one-shot --machine-hub -v 6 --agent-config-file ./examples/machinehub.yaml

data-gatherers:
# Gather Kubernetes OIDC information
- name: ark/oidc
kind: oidc

# Gather Kubernetes API server version information
- name: ark/discovery
kind: k8s-discovery
Expand Down
30 changes: 30 additions & 0 deletions examples/machinehub/input.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,34 @@
[
{
"data-gatherer": "ark/oidc",
"data": {
"openid_configuration": {
"id_token_signing_alg_values_supported": [
"RS256"
],
"issuer": "https://kubernetes.default.svc.cluster.local",
"jwks_uri": "https://10.10.1.2:6443/openid/v1/jwks",
"response_types_supported": [
"id_token"
],
"subject_types_supported": [
"public"
]
},
"jwks": {
"keys": [
{
"alg": "RS256",
"e": "AQAB",
"kid": "C-2916LkMJqepqULK2nqhq6uzVB6So_yyGnqyuor71Q",
"kty": "RSA",
"n": "sYh6rDpl5DyzBk8qlnYXo6Sf9WbplnXJv3tPxWTvhCFsVu9G5oWjknkafVDq5UOJrlybJJNjBmUyiEi1wbdnuhceJS7rZ3sRnNp3aNoS0omCR6iHJCOuoboSlcaPuRmYw4oWXlVUXlKyw8PYPVbNCcTLuq9nqf8y33mIqe7XJsf5-Z5P05WbK9Rzj-SJvlZLQ4dSFtIiwqLkm_2fpRLj0d8Af1F6vuztnhhUE2_PDsfIWdl_kJKkrK3B5x7k5tgTyFrNQPzlRBgK9jmK0HskwAFIDaLKb7FUWuUiQjn94rjKCED4iy201YPAoZBKIHFDlFVkQ_S3quwPcRyOS18r7w",
"use": "sig"
}
]
}
}
},
{
"data-gatherer": "ark/discovery",
"data": {
Expand Down
9 changes: 9 additions & 0 deletions internal/cyberark/dataupload/dataupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ type Snapshot struct {
ClusterDescription string `json:"cluster_description,omitempty"`
// K8SVersion is the version of Kubernetes which the cluster is running.
K8SVersion string `json:"k8s_version"`
// OIDCConfig contains OIDC configuration data from the API server's
// `/.well-known/openid-configuration` endpoint
OIDCConfig map[string]any `json:"openid_configuration,omitempty"`
// OIDCConfigError contains any error encountered while fetching the OIDC configuration
OIDCConfigError string `json:"openid_configuration_error,omitempty"`
// JWKS contains JWKS data from the API server's `/openid/v1/jwks` endpoint
JWKS map[string]any `json:"jwks,omitempty"`
// JWKSError contains any error encountered while fetching the JWKS
JWKSError string `json:"jwks_error,omitempty"`
// Secrets is a list of Secret resources in the cluster. Not all Secret
// types are included and only a subset of the Secret data is included.
Secrets []runtime.Object `json:"secrets"`
Expand Down
20 changes: 20 additions & 0 deletions pkg/client/client_cyberark.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,25 @@ func baseSnapshotFromOptions(opts Options) dataupload.Snapshot {
}
}

// extractOIDCFromReading converts the opaque data from a OIDCDiscoveryData
// data reading to allow access to the OIDC fields within.
func extractOIDCFromReading(reading *api.DataReading, target *dataupload.Snapshot) error {
if reading == nil {
return fmt.Errorf("programmer mistake: the DataReading must not be nil")
}
data, ok := reading.Data.(*api.OIDCDiscoveryData)
if !ok {
return fmt.Errorf(
"programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. "+
"This DataReading (%s) has data type %T", reading.DataGatherer, reading.Data)
}
target.OIDCConfig = data.OIDCConfig
target.OIDCConfigError = data.OIDCConfigError
target.JWKS = data.JWKS
target.JWKSError = data.JWKSError
return nil
}

// extractClusterIDAndServerVersionFromReading converts the opaque data from a DiscoveryData
// data reading to allow access to the Kubernetes version fields within.
func extractClusterIDAndServerVersionFromReading(reading *api.DataReading, target *dataupload.Snapshot) error {
Expand Down Expand Up @@ -149,6 +168,7 @@ func extractResourceListFromReading(reading *api.DataReading, target *[]runtime.
// and populates the relevant field(s) of the Snapshot based on the DataReading's data.
// Deleted resources are excluded from the snapshot because they are not needed by CyberArk.
var defaultExtractorFunctions = map[string]func(*api.DataReading, *dataupload.Snapshot) error{
"ark/oidc": extractOIDCFromReading,
"ark/discovery": extractClusterIDAndServerVersionFromReading,
"ark/secrets": func(r *api.DataReading, s *dataupload.Snapshot) error {
return extractResourceListFromReading(r, &s.Secrets)
Expand Down
64 changes: 64 additions & 0 deletions pkg/client/client_cyberark_convertdatareadings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,70 @@ func TestExtractServerVersionFromReading(t *testing.T) {
}
}

// TestExtractOIDCFromReading tests the extractOIDCFromReading function.
func TestExtractOIDCFromReading(t *testing.T) {
type testCase struct {
name string
reading *api.DataReading
expectedSnapshot dataupload.Snapshot
expectError string
}
tests := []testCase{
{
name: "nil reading",
expectError: `programmer mistake: the DataReading must not be nil`,
},
{
name: "nil data",
reading: &api.DataReading{
DataGatherer: "ark/oidc",
Data: nil,
},
expectError: `programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. This DataReading (ark/oidc) has data type <nil>`,
},
{
name: "wrong data type",
reading: &api.DataReading{
DataGatherer: "ark/oidc",
Data: &api.DiscoveryData{},
},
expectError: `programmer mistake: the DataReading must have data type *api.OIDCDiscoveryData. This DataReading (ark/oidc) has data type *api.DiscoveryData`,
},
{
name: "happy path",
reading: &api.DataReading{
DataGatherer: "ark/oidc",
Data: &api.OIDCDiscoveryData{
OIDCConfig: map[string]any{"issuer": "https://example.com"},
OIDCConfigError: "oidc-err",
JWKS: map[string]any{"keys": []any{}},
JWKSError: "jwks-err",
},
},
expectedSnapshot: dataupload.Snapshot{
OIDCConfig: map[string]any{"issuer": "https://example.com"},
OIDCConfigError: "oidc-err",
JWKS: map[string]any{"keys": []any{}},
JWKSError: "jwks-err",
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var snapshot dataupload.Snapshot
err := extractOIDCFromReading(test.reading, &snapshot)
if test.expectError != "" {
assert.EqualError(t, err, test.expectError)
assert.Equal(t, dataupload.Snapshot{}, snapshot)
return
}
require.NoError(t, err)
assert.Equal(t, test.expectedSnapshot, snapshot)
})
}
}

// TestExtractResourceListFromReading tests the extractResourceListFromReading function.
func TestExtractResourceListFromReading(t *testing.T) {
type testCase struct {
Expand Down
7 changes: 7 additions & 0 deletions pkg/client/client_cyberark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ func fakeReadings() []*api.DataReading {
}

return append([]*api.DataReading{
{
DataGatherer: "ark/oidc",
Data: &api.OIDCDiscoveryData{
OIDCConfigError: "Failed to fetch /.well-known/openid-configuration: 404 Not Found",
JWKSError: "Failed to fetch /openid/v1/jwks: 404 Not Found",
},
},
{
DataGatherer: "ark/discovery",
Data: &api.DiscoveryData{
Expand Down
2 changes: 1 addition & 1 deletion pkg/datagatherer/oidc/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (g *DataGathererOIDC) Fetch() (any, int, error) {
return ""
}

return api.OIDCDiscoveryData{
return &api.OIDCDiscoveryData{
OIDCConfig: oidcResponse,
OIDCConfigError: errToString(oidcErr),
JWKS: jwksResponse,
Expand Down
4 changes: 2 additions & 2 deletions pkg/datagatherer/oidc/oidc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func TestFetch_Success(t *testing.T) {
t.Fatalf("expected count 1, got %d", count)
}

res, ok := anyRes.(api.OIDCDiscoveryData)
res, ok := anyRes.(*api.OIDCDiscoveryData)
if !ok {
t.Fatalf("unexpected result type: %T", anyRes)
}
Expand Down Expand Up @@ -101,7 +101,7 @@ func TestFetch_Errors(t *testing.T) {
t.Fatalf("Fetch returned error: %v", err)
}

res, ok := anyRes.(api.OIDCDiscoveryData)
res, ok := anyRes.(*api.OIDCDiscoveryData)
if !ok {
t.Fatalf("unexpected result type: %T", anyRes)
}
Expand Down