Skip to content

Commit 0c0ac0f

Browse files
committed
WIP: Proof of concept / demo
Signed-off-by: Richard Wall <[email protected]>
1 parent 919c73d commit 0c0ac0f

File tree

10 files changed

+166
-133
lines changed

10 files changed

+166
-133
lines changed

hack/e2e/ca/config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
machineHub:
2+
subdomain: tlskp-test
3+
credentialsSecretName: todo-unused

hack/e2e/ca/test.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
#
3+
set -o nounset
4+
set -o errexit
5+
set -o pipefail
6+
7+
# CyberArk API configuration
8+
: ${ARK_USERNAME?}
9+
: ${ARK_SECRET?}
10+
: ${ARK_PLATFORM_DOMAIN?}
11+
: ${ARK_SUBDOMAIN?}
12+
13+
# The base URL of the OCI registry used for Docker images and Helm charts
14+
# E.g. ttl.sh/6ee49a01-c8ba-493e-bae9-4d8567574b56
15+
: ${OCI_BASE?}
16+
17+
k8s_namespace=cyberark
18+
19+
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
20+
root_dir=$(cd "${script_dir}/../../.." && pwd)
21+
export TERM=dumb
22+
23+
tmp_dir="$(mktemp -d /tmp/jetstack-secure.XXXXX)"
24+
25+
pushd "${tmp_dir}"
26+
> release.env
27+
make -C "$root_dir" release \
28+
OCI_SIGN_ON_PUSH=false \
29+
oci_platforms=linux/amd64 \
30+
oci_preflight_image_name=$OCI_BASE/images/venafi-agent \
31+
helm_chart_image_name=$OCI_BASE/charts/venafi-kubernetes-agent \
32+
GITHUB_OUTPUT="${tmp_dir}/release.env"
33+
source release.env
34+
35+
kind create cluster || true
36+
kubectl create ns "$k8s_namespace" || true
37+
38+
kubectl create secret generic agent-credentials \
39+
--namespace "$k8s_namespace" \
40+
--from-literal=ARK_USERNAME=$ARK_USERNAME \
41+
--from-literal=ARK_SECRET=$ARK_SECRET \
42+
--from-literal=ARK_PLATFORM_DOMAIN=$ARK_PLATFORM_DOMAIN \
43+
--from-literal=ARK_SUBDOMAIN=$ARK_SUBDOMAIN
44+
45+
helm upgrade agent "oci://${OCI_BASE}/charts/venafi-kubernetes-agent" \
46+
--install \
47+
--create-namespace \
48+
--namespace "$k8s_namespace" \
49+
--version "${RELEASE_HELM_CHART_VERSION}" \
50+
--set fullnameOverride=agent \
51+
--set "image.repository=${OCI_BASE}/images/venafi-agent" \
52+
--values "${script_dir}/values.agent.yaml"
53+
54+
kubectl scale -n "$k8s_namespace" deployment agent --replicas=0
55+
kubectl get cm -n "$k8s_namespace" agent-config -o jsonpath={.data.config\\.yaml} > config.original.yaml
56+
yq eval-all '. as $item ireduce ({}; . * $item)' config.original.yaml "${script_dir}/config.yaml" > config.yaml
57+
kubectl delete cm -n "$k8s_namespace" agent-config
58+
kubectl create cm -n "$k8s_namespace" agent-config --from-file=config.yaml
59+
kubectl scale -n "$k8s_namespace" deployment agent --replicas=1

hack/e2e/ca/values.agent.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Empty

pkg/agent/config.go

Lines changed: 24 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package agent
22

33
import (
4-
"errors"
54
"fmt"
65
"io"
76
"net/url"
@@ -62,9 +61,6 @@ type Config struct {
6261
ExcludeAnnotationKeysRegex []string `yaml:"exclude-annotation-keys-regex"`
6362
// Skips label keys that match the given set of regular expressions.
6463
ExcludeLabelKeysRegex []string `yaml:"exclude-label-keys-regex"`
65-
66-
// MachineHub holds config specific to MachineHub mode.
67-
MachineHub MachineHubConfig `yaml:"machineHub"`
6864
}
6965

7066
type Endpoint struct {
@@ -92,33 +88,6 @@ type VenafiCloudConfig struct {
9288
UploadPath string `yaml:"upload_path,omitempty"`
9389
}
9490

95-
// MachineHubConfig holds configuration values specific to the CyberArk Machine Hub integration
96-
type MachineHubConfig struct {
97-
// Subdomain is the subdomain indicating where data should be pushed. Used
98-
// for querying the Service Discovery Service to discover the Identity API
99-
// URL.
100-
Subdomain string `yaml:"subdomain"`
101-
102-
// CredentialsSecretName is the name of a Kubernetes Secret in the same
103-
// namespace as the agent, which will be watched for a username and password
104-
// to send to CyberArk Identity for authentication.
105-
CredentialsSecretName string `yaml:"credentialsSecretName"`
106-
}
107-
108-
func (mhc MachineHubConfig) Validate() error {
109-
var errs []error
110-
111-
if mhc.Subdomain == "" {
112-
errs = append(errs, fmt.Errorf("subdomain must not be empty in MachineHub mode"))
113-
}
114-
115-
if mhc.CredentialsSecretName == "" {
116-
errs = append(errs, fmt.Errorf("credentialsSecretName must not be empty in MachineHub mode"))
117-
}
118-
119-
return errors.Join(errs...)
120-
}
121-
12291
type AgentCmdFlags struct {
12392
// ConfigFilePath (--config-file, -c) is the path to the agent configuration
12493
// YAML file.
@@ -355,7 +324,7 @@ func InitAgentCmdFlags(c *cobra.Command, cfg *AgentCmdFlags) {
355324

356325
}
357326

358-
// TLSPKMode controls how to authenticate to TLSPK / Jetstack Secure. Only one
327+
// TLSPKMode controls how to authenticate to TLSPK / Jetstack Secure / MachineHub. Only one
359328
// TLSPKMode may be provided if using those backends.
360329
type TLSPKMode string
361330

@@ -364,10 +333,8 @@ const (
364333
JetstackSecureAPIToken TLSPKMode = "Jetstack Secure API Token"
365334
VenafiCloudKeypair TLSPKMode = "Venafi Cloud Key Pair Service Account"
366335
VenafiCloudVenafiConnection TLSPKMode = "Venafi Cloud VenafiConnection"
367-
368-
// It is possible to push to both MachineHub and TLSPK. With this mode, the
369-
// agent will only push to MachineHub and not to TLSPK.
370-
Off TLSPKMode = "MachineHub only"
336+
MachineHub TLSPKMode = "Machine Hub"
337+
Off TLSPKMode = "Off"
371338
)
372339

373340
// The command-line flags and the config file are combined into this struct by
@@ -408,11 +375,6 @@ type CombinedConfig struct {
408375
// Only used for testing purposes.
409376
OutputPath string
410377
InputPath string
411-
412-
// MachineHub-related settings.
413-
MachineHubMode bool
414-
MachineHubSubdomain string
415-
MachineHubCredentialsSecretName string
416378
}
417379

418380
// ValidateAndCombineConfig combines and validates the input configuration with
@@ -426,20 +388,6 @@ type CombinedConfig struct {
426388
// error.
427389
func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags) (CombinedConfig, client.Client, error) {
428390
res := CombinedConfig{}
429-
430-
if flags.MachineHubMode {
431-
if err := cfg.MachineHub.Validate(); err != nil {
432-
return CombinedConfig{}, nil, fmt.Errorf("invalid MachineHub config provided: %w", err)
433-
}
434-
435-
res.MachineHubMode = true
436-
res.MachineHubSubdomain = cfg.MachineHub.Subdomain
437-
res.MachineHubCredentialsSecretName = cfg.MachineHub.CredentialsSecretName
438-
439-
keysAndValues := []any{"credentialsSecretName", res.MachineHubCredentialsSecretName}
440-
log.V(logs.Info).Info("Will push to CyberArk MachineHub using a username and password loaded from a Kubernetes Secret", keysAndValues...)
441-
}
442-
443391
{
444392
var (
445393
mode TLSPKMode
@@ -472,23 +420,25 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
472420
case !flags.VenafiCloudMode && flags.CredentialsPath != "":
473421
mode = JetstackSecureOAuth
474422
reason = "--credentials-file was specified without --venafi-cloud"
475-
default:
476-
if !flags.MachineHubMode {
477-
return CombinedConfig{}, nil, fmt.Errorf("no TLSPK mode specified and MachineHub mode is disabled. You must either enable the MachineHub mode (using --machine-hub), or enable one of the TLSPK modes.\n" +
478-
"To enable one of the TLSPK modes, you can:\n" +
479-
" - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the " + string(VenafiCloudKeypair) + " mode.\n" +
480-
" - Use --venafi-connection for the " + string(VenafiCloudVenafiConnection) + " mode.\n" +
481-
" - Use --credentials-file alone if you want to use the " + string(JetstackSecureOAuth) + " mode.\n" +
482-
" - Use --api-token if you want to use the " + string(JetstackSecureAPIToken) + " mode.\n" +
483-
"Note that it is possible to use one of the TLSPK modes along with the MachineHub mode (--machine-hub).")
484-
}
485-
423+
case flags.MachineHubMode:
424+
mode = MachineHub
425+
reason = "--machine-hub was specified."
426+
case flags.OutputPath != "":
486427
mode = Off
428+
reason = "--output-path was specified. Data will be saved to a file. It will not be uploaded."
429+
default:
430+
return CombinedConfig{}, nil, fmt.Errorf("no upload mode specified. You must either enable one of the upload modes, or use --output-path to save data to a file.\n" +
431+
"To enable one of the upload modes, you can:\n" +
432+
" - Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the " + string(VenafiCloudKeypair) + " mode.\n" +
433+
" - Use --venafi-connection for the " + string(VenafiCloudVenafiConnection) + " mode.\n" +
434+
" - Use --credentials-file alone if you want to use the " + string(JetstackSecureOAuth) + " mode.\n" +
435+
" - Use --api-token if you want to use the " + string(JetstackSecureAPIToken) + " mode.\n" +
436+
" - Use --machine-hub if you want to use the " + string(MachineHub) + " mode.")
487437
}
488438

489439
keysAndValues = append(keysAndValues, "mode", mode, "reason", reason)
490440
if mode != Off {
491-
log.V(logs.Debug).Info("Configured to push to Venafi", keysAndValues...)
441+
log.V(logs.Debug).Info("Configured to push", keysAndValues...)
492442
}
493443

494444
res.TLSPKMode = mode
@@ -606,12 +556,12 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
606556
res.ClusterID = clusterID
607557
res.ClusterDescription = cfg.ClusterDescription
608558

609-
// Validation of `data-gatherers`.
610-
if dgErr := ValidateDataGatherers(cfg.DataGatherers); dgErr != nil {
611-
errs = multierror.Append(errs, dgErr)
612-
}
613-
res.DataGatherers = cfg.DataGatherers
614559
}
560+
// Validation of `data-gatherers`.
561+
if dgErr := ValidateDataGatherers(cfg.DataGatherers); dgErr != nil {
562+
errs = multierror.Append(errs, dgErr)
563+
}
564+
res.DataGatherers = cfg.DataGatherers
615565

616566
// Validation of --period, -p, and the `period` field, as well as
617567
// --backoff-max-time, --one-shot, and --strict. The flag --period/-p takes
@@ -807,6 +757,8 @@ func validateCredsAndCreateClient(log logr.Logger, flagCredentialsPath, flagClie
807757
if err != nil {
808758
errs = multierror.Append(errs, err)
809759
}
760+
case MachineHub:
761+
preflightClient = client.NewMachineHub()
810762
case Off:
811763
// No client needed in this mode.
812764
default:

pkg/agent/config_test.go

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
9696
withCmdLineFlags("--period", "99m", "--credentials-file", fakeCredsPath))
9797
require.NoError(t, err)
9898
assert.Equal(t, testutil.Undent(`
99-
INFO Configured to push to Venafi mode="Jetstack Secure OAuth" reason="--credentials-file was specified without --venafi-cloud"
99+
INFO Configured to push mode="Jetstack Secure OAuth" reason="--credentials-file was specified without --venafi-cloud"
100100
INFO Both the 'period' field and --period are set. Using the value provided with --period.
101101
`), gotLogs.String())
102102
assert.Equal(t, 99*time.Minute, got.Period)
@@ -178,7 +178,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
178178

179179
// The log line printed by pflag is not captured by the log recorder.
180180
assert.Equal(t, testutil.Undent(`
181-
INFO Configured to push to Venafi mode="Jetstack Secure OAuth" reason="--credentials-file was specified without --venafi-cloud"
181+
INFO Configured to push mode="Jetstack Secure OAuth" reason="--credentials-file was specified without --venafi-cloud"
182182
INFO Using period from config period="1h0m0s"
183183
`), b.String())
184184
})
@@ -194,13 +194,13 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
194194
withoutCmdLineFlags(),
195195
)
196196
assert.EqualError(t, err, testutil.Undent(`
197-
no TLSPK mode specified and MachineHub mode is disabled. You must either enable the MachineHub mode (using --machine-hub), or enable one of the TLSPK modes.
198-
To enable one of the TLSPK modes, you can:
197+
no upload mode specified. You must either enable one of the upload modes, or use --output-path to save data to a file.
198+
To enable one of the upload modes, you can:
199199
- Use (--venafi-cloud with --credentials-file) or (--client-id with --private-key-path) to use the Venafi Cloud Key Pair Service Account mode.
200200
- Use --venafi-connection for the Venafi Cloud VenafiConnection mode.
201201
- Use --credentials-file alone if you want to use the Jetstack Secure OAuth mode.
202202
- Use --api-token if you want to use the Jetstack Secure API Token mode.
203-
Note that it is possible to use one of the TLSPK modes along with the MachineHub mode (--machine-hub).`))
203+
- Use --machine-hub if you want to use the Machine Hub mode.`))
204204
assert.Nil(t, cl)
205205
})
206206

@@ -594,7 +594,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
594594
)
595595
require.NoError(t, err)
596596
assert.Equal(t, testutil.Undent(`
597-
INFO Configured to push to Venafi venConnName="venafi-components" mode="Venafi Cloud VenafiConnection" reason="--venafi-connection was specified"
597+
INFO Configured to push venConnName="venafi-components" mode="Venafi Cloud VenafiConnection" reason="--venafi-connection was specified"
598598
INFO ignoring the server field specified in the config file. In Venafi Cloud VenafiConnection mode, this field is not needed.
599599
INFO ignoring the venafi-cloud.upload_path field in the config file. In Venafi Cloud VenafiConnection mode, this field is not needed.
600600
INFO ignoring the venafi-cloud.uploader_id field in the config file. This field is not needed in Venafi Cloud VenafiConnection mode.
@@ -630,28 +630,7 @@ func Test_ValidateAndCombineConfig(t *testing.T) {
630630
`)),
631631
withCmdLineFlags("--machine-hub"))
632632
require.NoError(t, err)
633-
assert.Equal(t, Off, got.TLSPKMode)
634-
assert.Equal(t, true, got.MachineHubMode)
635-
})
636-
637-
t.Run("machinehub + venafi-cloud-keypair-auth should work simultaneously", func(t *testing.T) {
638-
t.Setenv("POD_NAMESPACE", "venafi")
639-
t.Setenv("KUBECONFIG", withFile(t, fakeKubeconfig))
640-
privKeyPath := withFile(t, fakePrivKeyPEM)
641-
got, _, err := ValidateAndCombineConfig(discardLogs(),
642-
withConfig(testutil.Undent(`
643-
machineHub:
644-
subdomain: foo
645-
credentialsSecretName: secret-1
646-
period: 1h
647-
venafi-cloud:
648-
upload_path: /v1/tlspk/upload/clusterdata
649-
cluster_id: foo
650-
`)),
651-
withCmdLineFlags("--machine-hub", "--venafi-cloud", "--client-id", "5bc7d07c-45da-11ef-a878-523f1e1d7de1", "--private-key-path", privKeyPath))
652-
require.NoError(t, err)
653-
assert.Equal(t, VenafiCloudKeypair, got.TLSPKMode)
654-
assert.Equal(t, true, got.MachineHubMode)
633+
assert.Equal(t, MachineHub, got.TLSPKMode)
655634
})
656635
}
657636

pkg/agent/run.go

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,6 @@ func gatherAndOutputData(ctx context.Context, eventf Eventf, config CombinedConf
345345
log.Info("Warning: PushingErr: retrying", "in", t, "reason", err)
346346
})
347347

348-
if config.MachineHubMode {
349-
post := func() (any, error) {
350-
log.Info("machine hub mode not yet implemented")
351-
return struct{}{}, nil
352-
}
353-
354-
group.Go(func() error {
355-
_, err := backoff.Retry(ctx, post, backoff.WithBackOff(backOff), backoff.WithNotify(notificationFunc), backoff.WithMaxElapsedTime(config.BackoffMaxTime))
356-
return err
357-
})
358-
}
359-
360348
if config.TLSPKMode != Off {
361349
post := func() (any, error) {
362350
return struct{}{}, postData(klog.NewContext(ctx, log), config, preflightClient, readings)
@@ -428,39 +416,31 @@ func gatherData(ctx context.Context, config CombinedConfig, dataGatherers map[st
428416

429417
func postData(ctx context.Context, config CombinedConfig, preflightClient client.Client, readings []*api.DataReading) error {
430418
log := klog.FromContext(ctx).WithName("postData")
431-
baseURL := config.Server
432-
433-
log.V(logs.Debug).Info("Posting data", "baseURL", baseURL)
434419

420+
var opts client.Options
435421
switch config.TLSPKMode { // nolint:exhaustive
436422
case VenafiCloudKeypair, VenafiCloudVenafiConnection:
437423
// orgID and clusterID are not required for Venafi Cloud auth
438-
err := preflightClient.PostDataReadingsWithOptions(ctx, readings, client.Options{
424+
opts = client.Options{
439425
ClusterName: config.ClusterID,
440426
ClusterDescription: config.ClusterDescription,
441-
})
442-
if err != nil {
443-
return fmt.Errorf("post to server failed: %+v", err)
444427
}
445-
log.Info("Data sent successfully")
446-
447-
return nil
448-
449428
case JetstackSecureOAuth, JetstackSecureAPIToken:
450-
err := preflightClient.PostDataReadingsWithOptions(ctx, readings, client.Options{
429+
opts = client.Options{
451430
OrgID: config.OrganizationID,
452431
ClusterID: config.ClusterID,
453-
})
454-
if err != nil {
455-
return fmt.Errorf("post to server failed: %+v", err)
456432
}
457-
log.Info("Data sent successfully")
458-
459-
return err
460-
433+
case MachineHub:
434+
// Machine hub client gets all its metadata from the data-readings.
461435
default:
462436
return fmt.Errorf("not implemented for mode %s", config.TLSPKMode)
463437
}
438+
439+
if err := preflightClient.PostDataReadingsWithOptions(ctx, readings, opts); err != nil {
440+
return fmt.Errorf("post to server failed: %+v", err)
441+
}
442+
log.Info("Data sent successfully")
443+
return nil
464444
}
465445

466446
// listenAndServe starts the supplied HTTP server and stops it gracefully when

0 commit comments

Comments
 (0)