diff --git a/api/v1alpha1/accessrequest_types.go b/api/v1alpha1/accessrequest_types.go index a7ba52b..fd6f8ee 100644 --- a/api/v1alpha1/accessrequest_types.go +++ b/api/v1alpha1/accessrequest_types.go @@ -20,28 +20,76 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +// Status defines the different stages a given access request can be +// at a given time. +// +kubebuilder:validation:Enum=requested;granted;expired;denied +type Status string + +const ( + // RequestedStatus is the stage that defines the access request as pending + RequestedStatus Status = "requested" + + // GrantedStatus is the stage that defines the access request as granted + GrantedStatus Status = "granted" + + // ExpiredStatus is the stage that defines the access request as expired + ExpiredStatus Status = "expired" + + // DeniedStatus is the stage that defines the access request as refused + DeniedStatus Status = "denied" +) // AccessRequestSpec defines the desired state of AccessRequest type AccessRequestSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file + // Duration defines the ammount of time that the elevated access + // will be granted once approved + Duration metav1.Duration `json:"duration"` + // TargetRoleName defines the role name the user will be assigned + // to once the access is approved + TargetRoleName string `json:"targetRoleName"` + // Application defines the Argo CD Application to assign the elevated + // permission + Application TargetApplication `json:"application"` + // Subjects defines the list of subjects for this access request + Subjects []Subject `json:"subjects"` +} + +// TargetRoleName defines the role name the user will be assigned +// to once the access is approved +type TargetApplication struct { + // Name refers to the Argo CD Application name + Name string `json:"name"` + // Namespace refers to the namespace where the Argo CD Application lives + Namespace string `json:"namespace"` +} - // Foo is an example field of AccessRequest. Edit accessrequest_types.go to remove/update - Foo string `json:"foo,omitempty"` +// Subject defines the user details to get elevated permissions assigned +type Subject struct { + // Username refers to the entity requesting the elevated permission + Username string `json:"username"` } // AccessRequestStatus defines the observed state of AccessRequest type AccessRequestStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file + Status Status `json:"status"` + ExpiresAt *metav1.Time `json:"expiresAt,omitempty"` + History []AccessRequetsHistory `json:"history,omitempty"` } -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status +// AccessRequetsHistory contain the history of all status transitions associated +// with this access request +type AccessRequetsHistory struct { + // TransitionTime is the time the transition is observed + TransitionTime metav1.Time `json:"transitionTime"` + // Status is the new status assigned to this access request + Status Status `json:"status"` + // Details may contain detailed information about the transition + Details *string `json:"details,omitempty"` +} // AccessRequest is the Schema for the accessrequests API +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status type AccessRequest struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -50,9 +98,8 @@ type AccessRequest struct { Status AccessRequestStatus `json:"status,omitempty"` } -// +kubebuilder:object:root=true - // AccessRequestList contains a list of AccessRequest +// +kubebuilder:object:root=true type AccessRequestList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6a11cfa..71ab09a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -29,8 +29,8 @@ func (in *AccessRequest) DeepCopyInto(out *AccessRequest) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec - out.Status = in.Status + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessRequest. @@ -86,6 +86,13 @@ func (in *AccessRequestList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessRequestSpec) DeepCopyInto(out *AccessRequestSpec) { *out = *in + out.Duration = in.Duration + out.Application = in.Application + if in.Subjects != nil { + in, out := &in.Subjects, &out.Subjects + *out = make([]Subject, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessRequestSpec. @@ -101,6 +108,17 @@ func (in *AccessRequestSpec) DeepCopy() *AccessRequestSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AccessRequestStatus) DeepCopyInto(out *AccessRequestStatus) { *out = *in + if in.ExpiresAt != nil { + in, out := &in.ExpiresAt, &out.ExpiresAt + *out = (*in).DeepCopy() + } + if in.History != nil { + in, out := &in.History, &out.History + *out = make([]AccessRequetsHistory, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessRequestStatus. @@ -112,3 +130,54 @@ func (in *AccessRequestStatus) DeepCopy() *AccessRequestStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AccessRequetsHistory) DeepCopyInto(out *AccessRequetsHistory) { + *out = *in + in.TransitionTime.DeepCopyInto(&out.TransitionTime) + if in.Details != nil { + in, out := &in.Details, &out.Details + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AccessRequetsHistory. +func (in *AccessRequetsHistory) DeepCopy() *AccessRequetsHistory { + if in == nil { + return nil + } + out := new(AccessRequetsHistory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Subject) DeepCopyInto(out *Subject) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Subject. +func (in *Subject) DeepCopy() *Subject { + if in == nil { + return nil + } + out := new(Subject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetApplication) DeepCopyInto(out *TargetApplication) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetApplication. +func (in *TargetApplication) DeepCopy() *TargetApplication { + if in == nil { + return nil + } + out := new(TargetApplication) + in.DeepCopyInto(out) + return out +} diff --git a/config/crd/bases/ephemeral-access.argoproj-labs.io_accessrequests.yaml b/config/crd/bases/ephemeral-access.argoproj-labs.io_accessrequests.yaml index f9fb99a..f48e5e0 100644 --- a/config/crd/bases/ephemeral-access.argoproj-labs.io_accessrequests.yaml +++ b/config/crd/bases/ephemeral-access.argoproj-labs.io_accessrequests.yaml @@ -39,13 +39,99 @@ spec: spec: description: AccessRequestSpec defines the desired state of AccessRequest properties: - foo: - description: Foo is an example field of AccessRequest. Edit accessrequest_types.go - to remove/update + application: + description: |- + Application defines the Argo CD Application to assign the elevated + permission + properties: + name: + description: Name refers to the Argo CD Application name + type: string + namespace: + description: Namespace refers to the namespace where the Argo + CD Application lives + type: string + required: + - name + - namespace + type: object + duration: + description: |- + Duration defines the ammount of time that the elevated access + will be granted once approved type: string + subjects: + description: Subjects defines the list of subjects for this access + request + items: + description: Subject defines the user details to get elevated permissions + assigned + properties: + username: + description: Username refers to the entity requesting the elevated + permission + type: string + required: + - username + type: object + type: array + targetRoleName: + description: |- + TargetRoleName defines the role name the user will be assigned + to once the access is approved + type: string + required: + - application + - duration + - subjects + - targetRoleName type: object status: description: AccessRequestStatus defines the observed state of AccessRequest + properties: + expiresAt: + format: date-time + type: string + history: + items: + description: |- + AccessRequetsHistory contain the history of all status transitions associated + with this access request + properties: + details: + description: Details may contain detailed information about + the transition + type: string + status: + description: Status is the new status assigned to this access + request + enum: + - requested + - granted + - expired + - denied + type: string + transitionTime: + description: TransitionTime is the time the transition is observed + format: date-time + type: string + required: + - status + - transitionTime + type: object + type: array + status: + description: |- + Status defines the different stages a given access request can be + at a given time. + enum: + - requested + - granted + - expired + - denied + type: string + required: + - status type: object type: object served: true diff --git a/internal/controller/accessrequest_controller_test.go b/internal/controller/accessrequest_controller_test.go index cf79e2e..1749fc5 100644 --- a/internal/controller/accessrequest_controller_test.go +++ b/internal/controller/accessrequest_controller_test.go @@ -38,7 +38,7 @@ var _ = Describe("AccessRequest Controller", func() { typeNamespacedName := types.NamespacedName{ Name: resourceName, - Namespace: "default", // TODO(user):Modify as needed + Namespace: "default", } accessrequest := &ephemeralaccessv1alpha1.AccessRequest{} @@ -47,11 +47,17 @@ var _ = Describe("AccessRequest Controller", func() { err := k8sClient.Get(ctx, typeNamespacedName, accessrequest) if err != nil && errors.IsNotFound(err) { resource := &ephemeralaccessv1alpha1.AccessRequest{ - ObjectMeta: metav1.ObjectMeta{ - Name: resourceName, - Namespace: "default", + TypeMeta: metav1.TypeMeta{ + Kind: "", + APIVersion: "", + }, + ObjectMeta: metav1.ObjectMeta{Name: resourceName, Namespace: "default"}, + Spec: ephemeralaccessv1alpha1.AccessRequestSpec{ + Duration: metav1.Duration{}, + TargetRoleName: "", + Application: ephemeralaccessv1alpha1.TargetApplication{}, + Subjects: []ephemeralaccessv1alpha1.Subject{}, }, - // TODO(user): Specify other spec details if needed. } Expect(k8sClient.Create(ctx, resource)).To(Succeed()) }