Skip to content

Commit

Permalink
add turnpike content guard
Browse files Browse the repository at this point in the history
Signed-off-by: Jonathan Holloway <[email protected]>
  • Loading branch information
loadtheaccumulator committed Nov 4, 2024
1 parent cb275e8 commit 9dcd572
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 6 deletions.
24 changes: 20 additions & 4 deletions pkg/clients/pulp/guards_composite.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/google/uuid"
"github.com/redhatinsights/edge-api/pkg/ptr"
feature "github.com/redhatinsights/edge-api/unleash/features"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -107,12 +108,27 @@ func (ps *PulpService) ContentGuardEnsure(ctx context.Context, orgID string) (*C
return nil, err
}

rcg, err := ps.RbacGuardEnsure(ctx)
if err != nil {
return nil, err
var contentGuardHref *string

if feature.PulpIntegrationTurnpikeGuard.IsEnabled() {
logrus.WithContext(ctx).Debug("Creating turnpike content guard")
tpcg, err := ps.TurnpikeGuardEnsure(ctx)
if err != nil {
return nil, err
}

contentGuardHref = tpcg.PulpHref
} else {
logrus.WithContext(ctx).Debug("Creating RBAC content guard")
rcg, err := ps.RbacGuardEnsure(ctx)
if err != nil {
return nil, err
}

contentGuardHref = rcg.PulpHref
}

ccg, err := ps.CompositeGuardEnsure(ctx, orgID, *hcg.PulpHref, *rcg.PulpHref)
ccg, err := ps.CompositeGuardEnsure(ctx, orgID, *hcg.PulpHref, *contentGuardHref)
if err != nil {
return nil, err
}
Expand Down
172 changes: 172 additions & 0 deletions pkg/clients/pulp/guards_turnpike.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package pulp

import (
"context"
"errors"
"fmt"

"github.com/google/uuid"
"github.com/redhatinsights/edge-api/config"
"github.com/redhatinsights/edge-api/pkg/ptr"
"github.com/sirupsen/logrus"
)

const TurnpikeGuardName = "ostree_turnpike_guard"
const TurnpikeJQFilter = ".identity.x509.subject_dn"

// TurnpikeGuardList returns a list of header guards. The nameFilter can be used to filter the results.
func (ps *PulpService) TurnpikeGuardList(ctx context.Context, nameFilter string) ([]HeaderContentGuardResponse, error) {
req := ContentguardsCoreHeaderListParams{
Limit: &DefaultPageSize,
}
if nameFilter != "" {
req.Name = &nameFilter
}

resp, err := ps.cwr.ContentguardsCoreHeaderListWithResponse(ctx, ps.dom, &req, addAuthenticationHeader)
if err != nil {
return nil, err
}

if resp.JSON200 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

if resp.JSON200.Count > DefaultPageSize {
return nil, fmt.Errorf("default page size too small: %d", resp.JSON200.Count)
}

if resp.JSON200.Count == 0 || resp.JSON200.Results[0].PulpHref == nil {
return nil, ErrRecordNotFound
}

return resp.JSON200.Results, nil
}

// TurnpikeGuardRead returns the Turnpike guard with the given ID.
func (ps *PulpService) TurnpikeGuardRead(ctx context.Context, id uuid.UUID) (*HeaderContentGuardResponse, error) {
req := ContentguardsCoreHeaderReadParams{}
resp, err := ps.cwr.ContentguardsCoreHeaderReadWithResponse(ctx, ps.dom, id, &req, addAuthenticationHeader)

if err != nil {
return nil, err
}

if resp.JSON200 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

return resp.JSON200, nil
}

// TurnpikeGuardFind returns the Turnpike guard.
func (ps *PulpService) TurnpikeGuardFind(ctx context.Context) (*HeaderContentGuardResponse, error) {
hgl, err := ps.TurnpikeGuardList(ctx, TurnpikeGuardName)
if err != nil {
logrus.WithFields(logrus.Fields{
"name": TurnpikeGuardName,
"error": err.Error(),
}).Error("Turnpike content guard not found")

if errors.Is(err, ErrRecordNotFound) {
return nil, ErrRecordNotFound
}

return nil, err
}

id := ScanUUID(hgl[0].PulpHref)
return ps.TurnpikeGuardRead(ctx, id)
}

// TurnpikeGuardCreate creates a new Turnpike guard and returns it.
func (ps *PulpService) TurnpikeGuardCreate(ctx context.Context) (*HeaderContentGuardResponse, error) {
cfg := config.Get()

req := HeaderContentGuard{
Name: TurnpikeGuardName,
Description: ptr.To("EDGE"),
HeaderName: "x-rh-identity",
HeaderValue: cfg.Pulp.GuardSubjectDN,
JqFilter: ptr.To(TurnpikeJQFilter),
}

resp, err := ps.cwr.ContentguardsCoreHeaderCreateWithResponse(ctx, ps.dom, req, addAuthenticationHeader)

if err != nil {
return nil, err
}

if resp.JSON201 == nil {
return nil, fmt.Errorf("unexpected response: %d, body: %s", resp.StatusCode(), string(resp.Body))
}

return resp.JSON201, nil
}

// TurnpikeGuardEnsure ensures that the Turnpike guard is created and returns it. The method is idempotent.
func (ps *PulpService) TurnpikeGuardEnsure(ctx context.Context) (*HeaderContentGuardResponse, error) {
cg, err := ps.TurnpikeGuardFind(ctx)
// nolint: gocritic
if errors.Is(err, ErrRecordNotFound) {
// turnpike guard is not found, so create one

cg, err = ps.TurnpikeGuardCreate(ctx)
if err != nil {
return nil, err
}

return cg, nil
} else if err != nil {
return nil, err
} else if cg == nil {
return nil, fmt.Errorf("unexpected nil guard")
}

return cg, nil
}

// TurnpikeGuardDelete deletes the Turnpike guard with the given ID.
func (ps *PulpService) TurnpikeGuardDelete(ctx context.Context, id uuid.UUID) error {
listParams := ContentguardsCoreHeaderListRolesParams{}
roles, err := ps.cwr.ContentguardsCoreHeaderListRolesWithResponse(ctx, ps.dom, id, &listParams, addAuthenticationHeader)

if err != nil {
return err
}

if roles.JSON200 == nil {
return fmt.Errorf("unexpected response: %d, body: %s", roles.StatusCode(), string(roles.Body))
}

for _, role := range roles.JSON200.Roles {
nr := NestedRole{
Role: role.Role,
Users: &[]string{},
}

logrus.WithContext(ctx).Warnf("removing Turnpike guardrole: %s", role.Role)
removed, err := ps.cwr.ContentguardsCoreHeaderRemoveRoleWithResponse(ctx, ps.dom, id, nr, addAuthenticationHeader)

if err != nil {
return err
}

if removed.JSON201 == nil {
return fmt.Errorf("unexpected response: %d, body: %s", removed.StatusCode(), string(removed.Body))
}
}

resp, err := ps.cwr.ContentguardsCoreHeaderDelete(ctx, ps.dom, id, addAuthenticationHeader)

if err != nil {
return err
}
resp.Body.Close()

if resp.StatusCode != 204 {
return fmt.Errorf("unexpected response: %d", resp.StatusCode)
}

return nil
}
5 changes: 3 additions & 2 deletions pkg/services/repostore/pulpstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/google/uuid"
"github.com/redhatinsights/edge-api/config"
"github.com/redhatinsights/edge-api/pkg/clients/pulp"
feature "github.com/redhatinsights/edge-api/unleash/features"

log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -172,8 +173,8 @@ func distributionURL(ctx context.Context, distBaseURL string, domain string, rep
distURL := prodDistURL.String()

// temporarily handle stage URLs so Image Builder worker can get to stage Pulp
if strings.Contains(distBaseURL, "stage") {
stagePulpURL := fmt.Sprintf("%s/api/pulp-content/%s/%s", cfg.PulpURL, domain, repoName)
if feature.PulpIntegrationSwapStageURL.IsEnabled() && strings.Contains(distBaseURL, "stage") {
stagePulpURL := fmt.Sprintf("%s/api/pulp-content/%s/%s", cfg.Pulp.URL, domain, repoName)
stageDistURL, err := url.Parse(stagePulpURL)
if err != nil {
return "", errors.New("Unable to set user:password for Pulp distribution URL")
Expand Down
6 changes: 6 additions & 0 deletions unleash/features/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ var PulpIntegrationDisableAWSRepoStore = &Flag{Name: "edge-management.pulp_integ
// PulpIntegrationUpdateViaPulp uses the Pulp Distribution URL for image and system updates
var PulpIntegrationUpdateViaPulp = &Flag{Name: "edge-management.pulp_integration_updateviapulp", EnvVar: "FEATURE_PULP_INTEGRATION_UPDATEVIAPULP"}

// PulpIntegrationSwapStageURL temporarily uses a specific URL for Image Builder to access Pulp in stage
var PulpIntegrationSwapStageURL = &Flag{Name: "edge-management.pulp_integration_swapstageurl", EnvVar: "FEATURE_PULP_INTEGRATION_SWAPSTAGEURL"}

// PulpIntegrationTurnpikeContentGuard enables and turnpike content guard and disables the RBAC content guard
var PulpIntegrationTurnpikeGuard = &Flag{Name: "edge-management.pulp_integration_turnpikeguard", EnvVar: "FEATURE_PULP_INTEGRATION_TURNPIKEGUARD"}

// (ADD FEATURE FLAGS ABOVE)
// FEATURE FLAG CHECK CODE

Expand Down

0 comments on commit 9dcd572

Please sign in to comment.