Skip to content
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

✨ Check for identityHash in APIExport admission and support multiple versions for APIs in permission claims #2169

Merged
merged 8 commits into from
Oct 17, 2022

Conversation

hasheddan
Copy link
Member

Summary

This patch set includes two primary changes:

Update the APIResourceSchema generation to consider multiple versions of
an API and append the schemas to one ARS rather than generating a
separate ARS for each.

Signed-off-by: hasheddan [email protected]

Adds an APIExport admission plugin that, for the time-being, only
validates that any permissionClaims for types that are not built-in
include an identityHash.

Signed-off-by: hasheddan [email protected]

The first can be observed when creating an APIExport with permissionClaims on FlowSchemas or PriorityLevelConfigurations.

Before:

πŸ€– (kxp) k -s https://192.168.1.189:6443/services/apiexport/root/kxp.crossplane.io/clusters/* api-versions
apiextensions.crossplane.io/v1
apiextensions.crossplane.io/v1alpha1
flowcontrol.apiserver.k8s.io/v1beta1
pkg.crossplane.io/v1
pkg.crossplane.io/v1alpha1
pkg.crossplane.io/v1beta1
secrets.crossplane.io/v1alpha1
v1

After:

πŸ€– (kxp) k -s https://192.168.1.189:6443/services/apiexport/root/kxp.crossplane.io/clusters/* api-versions
apiextensions.crossplane.io/v1
apiextensions.crossplane.io/v1alpha1
flowcontrol.apiserver.k8s.io/v1beta1
flowcontrol.apiserver.k8s.io/v1beta2
pkg.crossplane.io/v1
pkg.crossplane.io/v1alpha1
pkg.crossplane.io/v1beta1
secrets.crossplane.io/v1alpha1
v1

The second can be observed by trying to include a permissionClaim for something like Deployment (not built-in) without an identityHash:

πŸ€– (kxp) cat bad-export.yaml 
apiVersion: apis.kcp.dev/v1alpha1
kind: APIExport
metadata:
  name: data.my.domain
spec:
  latestResourceSchemas:
    - today.widgets.data.my.domain
  permissionClaims:
    - group: ""
      resource: "secrets"
    - group: ""
      resource: "configmaps"
    - group: ""
      resource: "namespaces"
    - group: "apps"
      resource: "deployments"
πŸ€– (kxp) k apply -f bad-export.yaml 
Error from server (Forbidden): error when creating "bad-export.yaml": apiexports.apis.kcp.dev "data.my.domain" is forbidden: spec.permissionClaims.[3].identityHash: Invalid value: "": identityHash is required for API types that are not built-in

Related issue(s)

Fixes #2161
xref #2152 (more work to be done on exposing conditions for other failure modes)

@openshift-ci openshift-ci bot added the kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API label Oct 11, 2022
@@ -57,7 +51,7 @@ func (c *APIReconciler) reconcile(ctx context.Context, apiDomainKey dynamicconte
}

// add built-in apiResourceSchema
for _, apiResourceSchema := range syncerSchemas {
for _, apiResourceSchema := range syncerbuiltin.SyncerSchemas {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the process of how we add the ARS to the sync target set can be improved here as we are essentially duplicating these for every apiSet even though we know they are always present. That being said, I opted to not include in this PR as it was already carrying a fairly large diff. Planning to address in follow-up.

"testing"

"github.com/stretchr/testify/require"
_ "k8s.io/kubernetes/pkg/apis/core/install"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider moving this anonymous import into builtin.go as inclusion of the package without also importing core install will cause init() to panic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like we should?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to, though in theory this is a change in behavior that is not strictly how all consumers would have to behave today. In practice, kcp is installing the core types into the legacy schema before this init() runs, but not all consumers have to. In general I don't love this pattern of registering schemas in init() calls, and would lean towards going ahead and moving the anonymous import (as you suggest) to cover the 99% case here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sttts what do you prefer?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sttts any thoughts here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't have much context here. But in general it is highly discourage to use the legacyscheme in any way, especially in new code like kcp. Create dedicated schemes and add the group you want via the AddToScheme methods.

@hasheddan
Copy link
Member Author

Need to cleanup some of these e2e tests that I believe are correctly failing now.

Update the APIResourceSchema generation to consider multiple versions of
an API and append the schemas to one ARS rather than generating a
separate ARS for each.

Signed-off-by: hasheddan <[email protected]>
Moves the APIExport built-in API ARS generation to a dedicated builtin
schema package and consume it in the APIExport reconciler. Methods are
broken out into a check of whether an ARS exists and a getter for the
actual ARS to accommodate more flexible use-cases.

Signed-off-by: hasheddan <[email protected]>
Moves the syncer built-in schema generation to a dedicated package such
that it can be consumed in multiple locations. Updates the syncer API
reconciler to use it as first consumer.

Signed-off-by: hasheddan <[email protected]>
Fixes up virtual worksapce e2e test to consume internal APIs from
built-in package.

Signed-off-by: hasheddan <[email protected]>
@hasheddan hasheddan force-pushed the admission-apiexport branch 3 times, most recently from 30c0882 to 870ca54 Compare October 11, 2022 17:35
field.Invalid(
field.NewPath("spec").
Child("permissionClaims").
Child(fmt.Sprintf("[%d]", i)).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use .Index here

type APIExportAdmission struct {
*admission.Handler

isBuiltInFn func(apisv1alpha1.GroupResource) bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would call this isBuiltIn

}

// NewAPIExportAdmission constructs a new APIExportAdmission admission plugin.
func NewAPIExportAdmission(isInternal func(apisv1alpha1.GroupResource) bool) *APIExportAdmission {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func NewAPIExportAdmission(isInternal func(apisv1alpha1.GroupResource) bool) *APIExportAdmission {
func NewAPIExportAdmission(isBuiltIn func(apisv1alpha1.GroupResource) bool) *APIExportAdmission {

func updateAttr(name string, obj runtime.Object, kind, resource string) admission.Attributes {
return admission.NewAttributesRecord(
helpers.ToUnstructuredOrDie(obj),
nil,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an update, I know it doesn't matter for the code under test, but should we fill in the "old" object here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to πŸ‘πŸ»

kind string
resource string
hasIdentity bool
isBuiltIn func(apisv1alpha1.GroupResource) bool
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless you're intending to vary the return based on the input, I think this can be a normal bool and you can set the function pointer once, inside t.Run?

pkg/admission/apiexport/admission_test.go Show resolved Hide resolved
pkg/admission/apiexport/admission_test.go Show resolved Hide resolved
"testing"

"github.com/stretchr/testify/require"
_ "k8s.io/kubernetes/pkg/apis/core/install"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like we should?

Adds an APIExport admission plugin that, for the time-being, only
validates that any permissionClaims for types that are not built-in
include an identityHash.

Signed-off-by: hasheddan <[email protected]>
Registers the APIExport admission plugin as a default.

Signed-off-by: hasheddan <[email protected]>
Adds hasheddan as a reviewer for the APIExport admission plugin.

Signed-off-by: hasheddan <[email protected]>
Cleans up some unecessary conditional logic in APIExport reconciler.

Signed-off-by: hasheddan <[email protected]>
@ncdc
Copy link
Member

ncdc commented Oct 12, 2022

/lgtm

Would like to hear Stefan's thoughts on the import question

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Oct 12, 2022
@hasheddan
Copy link
Member Author

/assign @sttts


func init() {
genericcontrolplane.Install(legacyscheme.Scheme)
schemes := []*runtime.Scheme{legacyscheme.Scheme}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this used for? don't like to see the legacyscheme in our code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sttts this isn’t strictly new in this patch set, just being relocated from the syncer API reconciler. I presume the legacy scheme is being used as the sync target is assumed to be Kubernetes API-compatible. Happy to update this to explicitly add each type in the internal API list below to the scheme.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend doing a follow-up to deal with legacyscheme usage as a whole

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ncdc happy to open a tracking issue and tackle πŸ‘πŸ»

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hasheddan yes let's do that please, thanks!

@hasheddan hasheddan requested a review from sttts October 17, 2022 16:07
@ncdc
Copy link
Member

ncdc commented Oct 17, 2022

Approving. Keep merging & iterate on πŸ˜„
/approve

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Oct 17, 2022

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ncdc

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 17, 2022
@openshift-merge-robot openshift-merge-robot merged commit b993bd9 into kcp-dev:main Oct 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. kind/api-change Categorizes issue or PR as related to adding, removing, or otherwise changing an API lgtm Indicates that a PR is ready to be merged.
Projects
None yet
4 participants