Skip to content

Commit dba92c3

Browse files
committed
WIP: Proof of concept / demo
Signed-off-by: Richard Wall <[email protected]>
1 parent 398cfd4 commit dba92c3

File tree

7 files changed

+86
-37
lines changed

7 files changed

+86
-37
lines changed

agent.yaml

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
server: "https://platform.jetstack.io"
2-
organization_id: "my-organization"
3-
cluster_id: "my_cluster"
4-
period: "0h1m0s"
5-
data-gatherers:
6-
- kind: "dummy"
7-
name: "dummy"
8-
config:
9-
failed-attempts: 5
10-
- kind: "dummy"
11-
name: "dummy-fail"
12-
config:
13-
always-fail: true
14-
venafi-cloud:
15-
uploader_id: "example-id"
16-
upload_path: "/example/endpoint/path"
17-
1+
machineHub:
2+
subdomain: adb-static
3+
credentialsSecretName: machinehub-credentials

pkg/agent/config.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,6 @@ func ValidateAndCombineConfig(log logr.Logger, cfg Config, flags AgentCmdFlags)
702702
if err != nil {
703703
return CombinedConfig{}, nil, multierror.Prefix(err, "validating creds:")
704704
}
705-
706705
return res, preflightClient, nil
707706
}
708707

pkg/agent/run.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"k8s.io/klog/v2"
3131
"sigs.k8s.io/controller-runtime/pkg/manager"
3232

33+
"github.com/jetstack/preflight/pkg/internal/cyberark/identity"
3334
"github.com/jetstack/preflight/api"
3435
"github.com/jetstack/preflight/pkg/client"
3536
"github.com/jetstack/preflight/pkg/clusteruid"
@@ -79,6 +80,23 @@ func Run(cmd *cobra.Command, args []string) (returnErr error) {
7980
return fmt.Errorf("While evaluating configuration: %v", err)
8081
}
8182

83+
var caClient *client.CyberArkClient
84+
{
85+
identityClient, err := identity.New(ctx, cfg.MachineHub.Subdomain)
86+
if err != nil {
87+
return fmt.Errorf("while creating the CyberArk identity client: %v", err)
88+
}
89+
username := os.Getenv("ARK_USERNAME")
90+
password := []byte(os.Getenv("ARK_SECRET"))
91+
if err := identityClient.LoginUsernamePassword(ctx, username, password); err != nil {
92+
return fmt.Errorf("while logging in: %v", err)
93+
}
94+
caClient, err = client.NewCyberArkClient(nil, cfg.MachineHub.Subdomain, identityClient.AuthenticateRequest)
95+
if err != nil {
96+
return fmt.Errorf("while creating the CyberArk dataupload client: %v", err)
97+
}
98+
}
99+
82100
// We need the cluster UID before we progress further so it can be sent along with other data readings
83101

84102
{
@@ -262,7 +280,7 @@ func Run(cmd *cobra.Command, args []string) (returnErr error) {
262280
// be cancelled, which will cause this blocking loop to exit
263281
// instead of waiting for the time period.
264282
for {
265-
if err := gatherAndOutputData(klog.NewContext(ctx, log), eventf, config, preflightClient, dataGatherers); err != nil {
283+
if err := gatherAndOutputData(klog.NewContext(ctx, log), eventf, config, preflightClient, caClient, dataGatherers); err != nil {
266284
return err
267285
}
268286

@@ -316,7 +334,7 @@ func newEventf(log logr.Logger, installNS string) (Eventf, error) {
316334
// Like Printf but for sending events to the agent's Pod object.
317335
type Eventf func(eventType, reason, msg string, args ...interface{})
318336

319-
func gatherAndOutputData(ctx context.Context, eventf Eventf, config CombinedConfig, preflightClient client.Client, dataGatherers map[string]datagatherer.DataGatherer) error {
337+
func gatherAndOutputData(ctx context.Context, eventf Eventf, config CombinedConfig, preflightClient client.Client, caClient *client.CyberArkClient, dataGatherers map[string]datagatherer.DataGatherer) error {
320338
log := klog.FromContext(ctx).WithName("gatherAndOutputData")
321339
var readings []*api.DataReading
322340

@@ -359,11 +377,19 @@ func gatherAndOutputData(ctx context.Context, eventf Eventf, config CombinedConf
359377
eventf("Warning", "PushingErr", "retrying in %v after error: %s", t, err)
360378
log.Info("Warning: PushingErr: retrying", "in", t, "reason", err)
361379
})
362-
363380
if config.MachineHubMode {
381+
clusterID := clusteruid.ClusterUIDFromContext(ctx)
382+
payload := api.DataReadingsPost{
383+
AgentMetadata: &api.AgentMetadata{
384+
Version: "",
385+
ClusterID: clusterID,
386+
},
387+
DataReadings: readings,
388+
}
364389
post := func() (any, error) {
365-
log.Info("machine hub mode not yet implemented")
366-
return struct{}{}, nil
390+
return struct{}{}, caClient.PostDataReadingsWithOptions(ctx, payload, client.CyberArkClientOptions{
391+
ClusterName: clusterID,
392+
})
367393
}
368394

369395
group.Go(func() error {

pkg/client/client_cyberark.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ import (
55
)
66

77
type CyberArkClient = dataupload.CyberArkClient
8+
type CyberArkClientOptions = dataupload.Options
89

910
var NewCyberArkClient = dataupload.NewCyberArkClient

pkg/internal/cyberark/dataupload/dataupload.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func (c *CyberArkClient) PostDataReadingsWithOptions(ctx context.Context, payloa
6464

6565
presignedUploadURL, err := c.retrievePresignedUploadURL(ctx, hex.EncodeToString(checksum.Sum(nil)), opts)
6666
if err != nil {
67-
return err
67+
return fmt.Errorf("while retrieving presigned upload URL: %v", err)
6868
}
6969

7070
req, err := http.NewRequestWithContext(ctx, http.MethodPost, presignedUploadURL, encodedBody)
@@ -120,7 +120,7 @@ func (c *CyberArkClient) retrievePresignedUploadURL(ctx context.Context, checksu
120120

121121
req.Header.Set("Content-Type", "application/json")
122122
if err := c.authenticateRequest(req); err != nil {
123-
return "", fmt.Errorf("failed to authenticate request")
123+
return "", fmt.Errorf("failed to authenticate request: %v", err)
124124
}
125125
version.SetUserAgent(req)
126126

pkg/internal/cyberark/identity/identity.go

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/cenkalti/backoff/v5"
1515
"k8s.io/klog/v2"
16+
"k8s.io/client-go/transport"
1617

1718
"github.com/jetstack/preflight/pkg/internal/cyberark/servicediscovery"
1819
"github.com/jetstack/preflight/pkg/logs"
@@ -209,11 +210,13 @@ func NewWithDiscoveryClient(ctx context.Context, discoveryClient *servicediscove
209210
if err != nil {
210211
return nil, err
211212
}
213+
httpClient := &http.Client{
214+
Timeout: 10 * time.Second,
215+
}
216+
httpClient.Transport = transport.DebugWrappers(http.DefaultTransport)
212217

213218
return &Client{
214-
client: &http.Client{
215-
Timeout: 10 * time.Second,
216-
},
219+
client: httpClient,
217220

218221
endpoint: endpoint,
219222
subdomain: subdomain,
@@ -277,23 +280,27 @@ func (c *Client) doStartAuthentication(ctx context.Context, username string) (ad
277280

278281
bodyJSON, err := json.Marshal(body)
279282
if err != nil {
283+
logger.Error(err, "")
280284
return response, fmt.Errorf("failed to marshal JSON for request to StartAuthentication endpoint: %s", err)
281285
}
282286

283287
endpoint, err := url.JoinPath(c.endpoint, "Security", "StartAuthentication")
284288
if err != nil {
289+
logger.Error(err, "")
285290
return response, fmt.Errorf("failed to create URL for request to CyberArk Identity StartAuthentication: %s", err)
286291
}
287292

288293
request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(bodyJSON))
289294
if err != nil {
295+
logger.Error(err, "")
290296
return response, fmt.Errorf("failed to initialise request to Identity endpoint %s: %s", endpoint, err)
291297
}
292298

293299
setIdentityHeaders(request)
294300

295301
httpResponse, err := c.client.Do(request)
296302
if err != nil {
303+
logger.Error(err, "")
297304
return response, fmt.Errorf("failed to perform HTTP request to start authentication: %s", err)
298305
}
299306

@@ -302,6 +309,7 @@ func (c *Client) doStartAuthentication(ctx context.Context, username string) (ad
302309
if httpResponse.StatusCode != http.StatusOK {
303310
err := fmt.Errorf("got unexpected status code %s from request to start authentication in CyberArk Identity API", httpResponse.Status)
304311
if httpResponse.StatusCode >= 500 || httpResponse.StatusCode < 400 {
312+
logger.Error(err, "")
305313
return response, err
306314
}
307315

@@ -315,55 +323,69 @@ func (c *Client) doStartAuthentication(ctx context.Context, username string) (ad
315323
err = json.NewDecoder(io.LimitReader(httpResponse.Body, maxStartAuthenticationBodySize)).Decode(&startAuthResponse)
316324
if err != nil {
317325
if err == io.ErrUnexpectedEOF {
326+
logger.Error(err, "")
318327
return response, fmt.Errorf("rejecting JSON response from server as it was too large or was truncated")
319328
}
320329

330+
logger.Error(err, "")
321331
return response, fmt.Errorf("failed to parse JSON from otherwise successful request to start authentication: %s", err)
322332
}
323333

324334
if !startAuthResponse.Success {
325-
return response, fmt.Errorf("got a failure response from request to start authentication: message=%q, error=%q", startAuthResponse.Message, startAuthResponse.ErrorID)
335+
err := fmt.Errorf("got a failure response from request to start authentication: message=%q, error=%q", startAuthResponse.Message, startAuthResponse.ErrorID)
336+
logger.Error(err, "")
337+
return response, err
326338
}
327339

328340
logger.V(logs.Debug).Info("made successful request to StartAuthentication", "summary", startAuthResponse.Result.Summary)
329341

330342
if startAuthResponse.Result.Summary != SummaryNewPackage {
331343
// This means we can't respond to whatever summary the server sent.
332344
// The best thing to do is try and find a challenge we can solve anyway.
333-
klog.FromContext(ctx).Info("got an unexpected Summary from StartAuthentication response; will attempt to complete a login challenge anyway", "summary", startAuthResponse.Result.Summary)
345+
logger.Info("got an unexpected Summary from StartAuthentication response; will attempt to complete a login challenge anyway", "summary", startAuthResponse.Result.Summary)
334346
}
335347

336348
// We can only handle a UP type challenge, and if there are any other challenges, we'll have to fail because we can't handle them.
337349
// https://github.com/cyberark/ark-sdk-python/blob/3be12c3f2d3a2d0407025028943e584b6edc5996/ark_sdk_python/auth/identity/ark_identity.py#L405
338350
switch len(startAuthResponse.Result.Challenges) {
339351
case 0:
340-
return response, fmt.Errorf("got no valid challenges in response to start authentication; unable to log in")
352+
err := fmt.Errorf("got no valid challenges in response to start authentication; unable to log in")
353+
logger.Error(err, "")
354+
return response, err
341355

342356
case 1:
343357
// do nothing, this is ideal
344358

345359
default:
346-
return response, fmt.Errorf("got %d challenges in response to start authentication, which means MFA may be enabled; unable to log in", len(startAuthResponse.Result.Challenges))
360+
err := fmt.Errorf("got %d challenges in response to start authentication, which means MFA may be enabled; unable to log in", len(startAuthResponse.Result.Challenges))
361+
logger.Error(err, "")
362+
return response, err
347363
}
348364

349365
challenge := startAuthResponse.Result.Challenges[0]
350366

351367
switch len(challenge.Mechanisms) {
352368
case 0:
353369
// presumably this shouldn't happen, but handle the case anyway
354-
return response, fmt.Errorf("got no mechanisms for challenge from Identity server")
370+
err := fmt.Errorf("got no mechanisms for challenge from Identity server")
371+
logger.Error(err, "")
372+
return response, err
355373

356374
case 1:
357375
// do nothing, this is ideal
358376

359377
default:
360-
return response, fmt.Errorf("got %d mechanisms in response to start authentication, which means MFA may be enabled; unable to log in", len(challenge.Mechanisms))
378+
err := fmt.Errorf("got %d mechanisms in response to start authentication, which means MFA may be enabled; unable to log in", len(challenge.Mechanisms))
379+
logger.Error(err, "")
380+
return response, err
361381
}
362382

363383
mechanism := challenge.Mechanisms[0]
364384

365385
if !mechanism.Enrolled || mechanism.Name != MechanismUsernamePassword {
366-
return response, errNoUPMechanism
386+
err := errNoUPMechanism
387+
logger.Error(err, "")
388+
return response, err
367389
}
368390

369391
response.Action = ActionAnswer
@@ -378,6 +400,10 @@ func (c *Client) doStartAuthentication(ctx context.Context, username string) (ad
378400
// doAdvanceAuthentication performs the second step of the login process, sending the password to the server
379401
// and receiving a token in response.
380402
func (c *Client) doAdvanceAuthentication(ctx context.Context, username string, password *[]byte, requestBody advanceAuthenticationRequestBody) error {
403+
404+
logger := klog.FromContext(ctx)
405+
406+
381407
if password == nil {
382408
return backoff.Permanent(fmt.Errorf("password must not be nil; this is a programming error"))
383409
}
@@ -396,13 +422,15 @@ func (c *Client) doAdvanceAuthentication(ctx context.Context, username string, p
396422

397423
request, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(bodyJSON))
398424
if err != nil {
425+
logger.Error(err, "")
399426
return fmt.Errorf("failed to initialise request to Identity endpoint %s: %s", endpoint, err)
400427
}
401428

402429
setIdentityHeaders(request)
403430

404431
httpResponse, err := c.client.Do(request)
405432
if err != nil {
433+
logger.Error(err, "")
406434
return fmt.Errorf("failed to perform HTTP request to advance authentication: %s", err)
407435
}
408436

@@ -413,6 +441,7 @@ func (c *Client) doAdvanceAuthentication(ctx context.Context, username string, p
413441
if httpResponse.StatusCode != http.StatusOK {
414442
err := fmt.Errorf("got unexpected status code %s from request to advance authentication in CyberArk Identity API", httpResponse.Status)
415443
if httpResponse.StatusCode >= 500 || httpResponse.StatusCode < 400 {
444+
logger.Error(err, "")
416445
return err
417446
}
418447

@@ -425,14 +454,19 @@ func (c *Client) doAdvanceAuthentication(ctx context.Context, username string, p
425454
err = json.NewDecoder(io.LimitReader(httpResponse.Body, maxAdvanceAuthenticationBodySize)).Decode(&advanceAuthResponse)
426455
if err != nil {
427456
if err == io.ErrUnexpectedEOF {
457+
logger.Error(err, "")
428458
return fmt.Errorf("rejecting JSON response from server as it was too large or was truncated")
429459
}
430460

461+
logger.Error(err, "")
431462
return fmt.Errorf("failed to parse JSON from otherwise successful request to advance authentication: %s", err)
432463
}
433464

434465
if !advanceAuthResponse.Success {
435-
return fmt.Errorf("got a failure response from request to advance authentication: message=%q, error=%q", advanceAuthResponse.Message, advanceAuthResponse.ErrorID)
466+
// TODO: Permanent error?
467+
err := fmt.Errorf("got a failure response from request to advance authentication: message=%q, error=%q", advanceAuthResponse.Message, advanceAuthResponse.ErrorID)
468+
logger.Error(err, "")
469+
return err
436470
}
437471

438472
if advanceAuthResponse.Result.Summary != SummaryLoginSuccess {
@@ -441,7 +475,7 @@ func (c *Client) doAdvanceAuthentication(ctx context.Context, username string, p
441475
return backoff.Permanent(fmt.Errorf("got a %s response from AdvanceAuthentication; this implies that the user account %s requires MFA, which is not supported. Try unlocking MFA for this user", advanceAuthResponse.Result.Summary, username))
442476
}
443477

444-
klog.FromContext(ctx).Info("successfully completed AdvanceAuthentication request to CyberArk Identity; login complete", "username", username)
478+
logger.Info("successfully completed AdvanceAuthentication request to CyberArk Identity; login complete", "username", username)
445479

446480
c.tokenCachedMutex.Lock()
447481

pkg/internal/cyberark/servicediscovery/discovery.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"net/url"
1010
"time"
1111

12+
"k8s.io/client-go/transport"
13+
1214
"github.com/jetstack/preflight/pkg/version"
1315
)
1416

@@ -63,6 +65,7 @@ func New(clientOpts ...ClientOpt) *Client {
6365
client := &Client{
6466
client: &http.Client{
6567
Timeout: 10 * time.Second,
68+
Transport: transport.DebugWrappers(http.DefaultTransport),
6669
},
6770
endpoint: prodDiscoveryEndpoint,
6871
}

0 commit comments

Comments
 (0)