Skip to content

[VC-43753] CyberArk Discovery and Context: Use a namespaces datagatherer to get the cluster ID #687

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: VC-43403-inventory-api-2
Choose a base branch
from
Draft
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
23 changes: 0 additions & 23 deletions pkg/agent/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (

"github.com/jetstack/preflight/api"
"github.com/jetstack/preflight/pkg/client"
"github.com/jetstack/preflight/pkg/clusteruid"
"github.com/jetstack/preflight/pkg/datagatherer"
"github.com/jetstack/preflight/pkg/datagatherer/k8s"
"github.com/jetstack/preflight/pkg/kubeconfig"
Expand Down Expand Up @@ -79,28 +78,6 @@ func Run(cmd *cobra.Command, args []string) (returnErr error) {
return fmt.Errorf("While evaluating configuration: %v", err)
}

// We need the cluster UID before we progress further so it can be sent along with other data readings

{
restCfg, err := kubeconfig.LoadRESTConfig("")
if err != nil {
return err
}

clientset, err := kubernetes.NewForConfig(restCfg)
if err != nil {
return err
}

ctx, err = clusteruid.GetClusterUID(ctx, clientset)
if err != nil {
return fmt.Errorf("failed to get cluster UID: %v", err)
}

clusterUID := clusteruid.ClusterUIDFromContext(ctx)
log.V(logs.Debug).Info("Retrieved cluster UID", "clusterUID", clusterUID)
}

group, gctx := errgroup.WithContext(ctx)
defer func() {
cancel()
Expand Down
45 changes: 0 additions & 45 deletions pkg/clusteruid/clusteruid.go

This file was deleted.

39 changes: 0 additions & 39 deletions pkg/clusteruid/clusteruid_test.go

This file was deleted.

18 changes: 5 additions & 13 deletions pkg/internal/cyberark/dataupload/dataupload.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ type CyberArkClient struct {
authenticateRequest func(req *http.Request) error
}

type Options struct {
ClusterName string
}

func NewCyberArkClient(trustedCAs *x509.CertPool, baseURL string, authenticateRequest func(req *http.Request) error) (*CyberArkClient, error) {
cyberClient := &http.Client{}
tr := http.DefaultTransport.(*http.Transport).Clone()
Expand All @@ -55,14 +51,10 @@ func NewCyberArkClient(trustedCAs *x509.CertPool, baseURL string, authenticateRe
}, nil
}

// PostDataReadingsWithOptions PUTs the supplied payload to an [AWS presigned URL] which it obtains via the CyberArk inventory API.
// PostDataReadings PUTs the supplied payload to an [AWS presigned URL] which it obtains via the CyberArk inventory API.
//
// [AWS presigned URL]: https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, readings []*api.DataReading, opts Options) error {
if opts.ClusterName == "" {
return fmt.Errorf("programmer mistake: the cluster name (aka `cluster_id` in the config file) cannot be left empty")
}

func (c *CyberArkClient) PostDataReadings(ctx context.Context, readings []*api.DataReading) error {
snapshot, err := convertDataReadingsToCyberarkSnapshot(readings)
if err != nil {
return fmt.Errorf("while converting datareadings to Cyberark snapshot format: %s", err)
Expand All @@ -74,7 +66,7 @@ func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, readin
return err
}

presignedUploadURL, err := c.retrievePresignedUploadURL(ctx, hex.EncodeToString(checksum.Sum(nil)), opts)
presignedUploadURL, err := c.retrievePresignedUploadURL(ctx, hex.EncodeToString(checksum.Sum(nil)), snapshot.ClusterID)
if err != nil {
return fmt.Errorf("while retrieving snapshot upload URL: %s", err)
}
Expand Down Expand Up @@ -104,7 +96,7 @@ func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, readin
return nil
}

func (c *CyberArkClient) retrievePresignedUploadURL(ctx context.Context, checksum string, opts Options) (string, error) {
func (c *CyberArkClient) retrievePresignedUploadURL(ctx context.Context, checksum string, clusterID string) (string, error) {
uploadURL, err := url.JoinPath(c.baseURL, apiPathSnapshotLinks)
if err != nil {
return "", err
Expand All @@ -115,7 +107,7 @@ func (c *CyberArkClient) retrievePresignedUploadURL(ctx context.Context, checksu
Checksum string `json:"checksum_sha3"`
AgentVersion string `json:"agent_version"`
}{
ClusterID: opts.ClusterName,
ClusterID: clusterID,
Checksum: checksum,
AgentVersion: version.PreflightVersion,
}
Expand Down
86 changes: 51 additions & 35 deletions pkg/internal/cyberark/dataupload/dataupload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
"net/http"
"os"
"testing"
"time"

"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog/v2"
"k8s.io/klog/v2/ktesting"

Expand All @@ -23,20 +24,41 @@ import (
_ "k8s.io/klog/v2/ktesting/init"
)

func TestCyberArkClient_PostDataReadingsWithOptions_MockAPI(t *testing.T) {
fakeTime := time.Unix(123, 0)
defaultDataReadings := []*api.DataReading{
{
ClusterID: "success-cluster-id",
DataGatherer: "test-gatherer",
Timestamp: api.Time{Time: fakeTime},
Data: map[string]interface{}{"test": "data"},
SchemaVersion: "v1",
func genNamespace(name string) *unstructured.Unstructured {
o := &unstructured.Unstructured{}
o.SetAPIVersion("")
o.SetKind("Namespace")
o.SetName(name)
return o
}
func genArkNamespacesDataReading(clusterID types.UID) *api.DataReading {
kubeSystemNamespace := genNamespace("kube-system")
kubeSystemNamespace.SetUID(clusterID)
return &api.DataReading{
ClusterID: "ignored-tlspk-cluster-id",
DataGatherer: "ark/namespaces",
Data: &api.DynamicData{
Items: []*api.GatheredResource{
{
Resource: kubeSystemNamespace,
},
{
Resource: genNamespace("kube-public"),
},
{
Resource: genNamespace("venafi"),
},
{
Resource: genNamespace("cert-manager"),
},
},
},
SchemaVersion: "v1",
}

defaultOpts := dataupload.Options{
ClusterName: "success-cluster-id",
}
func TestCyberArkClient_PostDataReadings_MockAPI(t *testing.T) {
defaultDataReadings := []*api.DataReading{
genArkNamespacesDataReading("success-cluster-id"),
}

setToken := func(token string) func(*http.Request) error {
Expand All @@ -50,31 +72,27 @@ func TestCyberArkClient_PostDataReadingsWithOptions_MockAPI(t *testing.T) {
name string
readings []*api.DataReading
authenticate func(req *http.Request) error
opts dataupload.Options
requireFn func(t *testing.T, err error)
}{
{
name: "successful upload",
readings: defaultDataReadings,
opts: defaultOpts,
authenticate: setToken("success-token"),
requireFn: func(t *testing.T, err error) {
require.NoError(t, err)
},
},
{
name: "error when cluster name is empty",
readings: defaultDataReadings,
opts: dataupload.Options{ClusterName: ""},
name: "error when cluster ID not found among data readings",
readings: nil,
authenticate: setToken("success-token"),
requireFn: func(t *testing.T, err error) {
require.ErrorContains(t, err, "programmer mistake: the cluster name")
require.ErrorContains(t, err, "while converting datareadings to Cyberark snapshot format: failed to compute a clusterID from the data-readings")
},
},
{
name: "error when bearer token is incorrect",
readings: defaultDataReadings,
opts: defaultOpts,
authenticate: setToken("fail-token"),
requireFn: func(t *testing.T, err error) {
require.ErrorContains(t, err, "while retrieving snapshot upload URL: received response with status code 500: should authenticate using the correct bearer token")
Expand All @@ -83,7 +101,6 @@ func TestCyberArkClient_PostDataReadingsWithOptions_MockAPI(t *testing.T) {
{
name: "error contains authenticate error",
readings: defaultDataReadings,
opts: defaultOpts,
authenticate: func(_ *http.Request) error {
return errors.New("simulated-authenticate-error")
},
Expand All @@ -92,18 +109,20 @@ func TestCyberArkClient_PostDataReadingsWithOptions_MockAPI(t *testing.T) {
},
},
{
name: "invalid JSON from server (RetrievePresignedUploadURL step)",
readings: defaultDataReadings,
opts: dataupload.Options{ClusterName: "invalid-json-retrieve-presigned"},
name: "invalid JSON from server (RetrievePresignedUploadURL step)",
readings: []*api.DataReading{
genArkNamespacesDataReading("invalid-json-retrieve-presigned"),
},
authenticate: setToken("success-token"),
requireFn: func(t *testing.T, err error) {
require.ErrorContains(t, err, "while retrieving snapshot upload URL: rejecting JSON response from server as it was too large or was truncated")
},
},
{
name: "500 from server (RetrievePresignedUploadURL step)",
readings: defaultDataReadings,
opts: dataupload.Options{ClusterName: "invalid-response-post-data"},
name: "500 from server (RetrievePresignedUploadURL step)",
readings: []*api.DataReading{
genArkNamespacesDataReading("invalid-response-post-data"),
},
authenticate: setToken("success-token"),
requireFn: func(t *testing.T, err error) {
require.ErrorContains(t, err, "while retrieving snapshot upload URL: received response with status code 500: mock error")
Expand All @@ -128,22 +147,22 @@ func TestCyberArkClient_PostDataReadingsWithOptions_MockAPI(t *testing.T) {
cyberArkClient, err := dataupload.NewCyberArkClient(certPool, server.Server.URL, tc.authenticate)
require.NoError(t, err)

err = cyberArkClient.PostDataReadingsWithOptions(ctx, tc.readings, tc.opts)
err = cyberArkClient.PostDataReadings(ctx, tc.readings)
tc.requireFn(t, err)
})
}
}

// TestCyberArkClient_PostDataReadingsWithOptions_RealAPI demonstrates that the dataupload code works with the real inventory API.
// TestCyberArkClient_PostDataReadings_RealAPI demonstrates that the dataupload code works with the real inventory API.
// An API token is obtained by authenticating with the ARK_USERNAME and ARK_SECRET from the environment.
// ARK_SUBDOMAIN should be your tenant subdomain.
// ARK_PLATFORM_DOMAIN should be either integration-cyberark.cloud or cyberark.cloud
//
// To enable verbose request logging:
//
// go test ./pkg/internal/cyberark/dataupload/... \
// -v -count 1 -run TestCyberArkClient_PostDataReadingsWithOptions_RealAPI -args -testing.v 6
func TestCyberArkClient_PostDataReadingsWithOptions_RealAPI(t *testing.T) {
// -v -count 1 -run TestCyberArkClient_PostDataReadings_RealAPI -args -testing.v 6
func TestCyberArkClient_PostDataReadings_RealAPI(t *testing.T) {
platformDomain := os.Getenv("ARK_PLATFORM_DOMAIN")
subdomain := os.Getenv("ARK_SUBDOMAIN")
username := os.Getenv("ARK_USERNAME")
Expand Down Expand Up @@ -183,12 +202,9 @@ func TestCyberArkClient_PostDataReadingsWithOptions_RealAPI(t *testing.T) {
require.NoError(t, err)

dataReadings := testutil.ParseDataReadings(t, testutil.ReadGZIP(t, "testdata/example-1/datareadings.json.gz"))
err = cyberArkClient.PostDataReadingsWithOptions(
err = cyberArkClient.PostDataReadings(
ctx,
dataReadings,
dataupload.Options{
ClusterName: "bb068932-c80d-460d-88df-34bc7f3f3297",
},
)
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion pkg/internal/cyberark/dataupload/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (mds *mockDataUploadServer) handlePresignedUpload(w http.ResponseWriter, r
}

if req.ClusterID != successClusterID {
http.Error(w, "post body contains cluster ID", http.StatusInternalServerError)
http.Error(w, "post body does not contain cluster ID", http.StatusInternalServerError)
return
}

Expand Down
Loading