Skip to content
Open
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
8 changes: 8 additions & 0 deletions config/crd/bases/crds.wizardofoz.co_execaccessrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ spec:
spec:
description: ExecAccessRequestSpec defines the desired state of ExecAccessRequest
properties:
clientKubeContext:
description: |-
ClientKubeContext is the name of the kubeconfig context that the client (typically `ozctl`)
was using when it created this request. The controller does not act on this value; it is
surfaced to the `accessCommand` template as `{{ .ClientKubeContext }}` so the rendered
command can include `--context <name>` and target the same cluster the request was created
in. Populated automatically by `ozctl`; safe to omit when applying YAML directly.
type: string
duration:
description: |-
Duration sets the length of time from the `spec.creationTimestamp` that this object will live. After the
Expand Down
12 changes: 11 additions & 1 deletion config/crd/bases/crds.wizardofoz.co_execaccesstemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,17 @@ spec:
}} -- /bin/sh
description: |-
AccessCommand is used to describe to the user how they can make use of their temporary access.
The AccessCommand can reference data from a Pod ObjectMeta.

The string is rendered as a Go text/template with the following variables available:

- `{{ .Metadata }}`: the target Pod's ObjectMeta (e.g. `{{ .Metadata.Name }}`,
`{{ .Metadata.Namespace }}`).
- `{{ .ClientKubeContext }}`: the kubeconfig context the request was created in,
populated automatically by `ozctl`. May be the empty string if the request was
applied as raw YAML or by an older `ozctl` that did not set the field. To be
safe in either case, gate references with a conditional, e.g.:

kubectl {{ if .ClientKubeContext }}--context {{ .ClientKubeContext }} {{ end }}exec -ti -n {{ .Metadata.Namespace }} {{ .Metadata.Name }} -- /bin/sh
type: string
allowedGroups:
description: |-
Expand Down
8 changes: 8 additions & 0 deletions config/crd/bases/crds.wizardofoz.co_podaccessrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ spec:
spec:
description: PodAccessRequestSpec defines the desired state of AccessRequest
properties:
clientKubeContext:
description: |-
ClientKubeContext is the name of the kubeconfig context that the client (typically `ozctl`)
was using when it created this request. The controller does not act on this value; it is
surfaced to the `accessCommand` template as `{{ .ClientKubeContext }}` so the rendered
command can include `--context <name>` and target the same cluster the request was created
in. Populated automatically by `ozctl`; safe to omit when applying YAML directly.
type: string
duration:
description: |-
Duration sets the length of time from the `spec.creationTimestamp` that this object will live. After the
Expand Down
83 changes: 76 additions & 7 deletions config/crd/bases/crds.wizardofoz.co_podaccesstemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,17 @@ spec:
}} -- /bin/sh
description: |-
AccessCommand is used to describe to the user how they can make use of their temporary access.
The AccessCommand can reference data from a Pod ObjectMeta.

The string is rendered as a Go text/template with the following variables available:

- `{{ .Metadata }}`: the target Pod's ObjectMeta (e.g. `{{ .Metadata.Name }}`,
`{{ .Metadata.Namespace }}`).
- `{{ .ClientKubeContext }}`: the kubeconfig context the request was created in,
populated automatically by `ozctl`. May be the empty string if the request was
applied as raw YAML or by an older `ozctl` that did not set the field. To be
safe in either case, gate references with a conditional, e.g.:

kubectl {{ if .ClientKubeContext }}--context {{ .ClientKubeContext }} {{ end }}exec -ti -n {{ .Metadata.Namespace }} {{ .Metadata.Name }} -- /bin/sh
type: string
allowedGroups:
description: |-
Expand Down Expand Up @@ -2309,7 +2319,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents resource
resize policy for the container.
Expand Down Expand Up @@ -5518,7 +5530,9 @@ spec:
type: integer
type: object
resizePolicy:
description: Resources resize policy for the container.
description: |-
Resources resize policy for the container.
This field cannot be set on ephemeral containers.
items:
description: ContainerResizePolicy represents resource
resize policy for the container.
Expand Down Expand Up @@ -6304,8 +6318,8 @@ spec:
will be made available to those containers which consume them
by name.

This is an alpha field and requires enabling the
DynamicResourceAllocation feature gate.
This is a stable field but requires that the
DynamicResourceAllocation feature gate is enabled.

This field is immutable.
items:
Expand Down Expand Up @@ -6763,9 +6777,10 @@ spec:
operator:
description: |-
Operator represents a key's relationship to the value.
Valid operators are Exists and Equal. Defaults to Equal.
Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal.
Exists is equivalent to wildcard for value, so that a pod can
tolerate all taints of a particular category.
Lt and Gt perform numeric comparisons (requires feature gate TaintTolerationComparisonOperators).
type: string
tolerationSeconds:
description: |-
Expand Down Expand Up @@ -7555,7 +7570,7 @@ spec:
resources:
description: |-
resources represents the minimum resources the volume should have.
If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements
Users are allowed to specify resource requirements
that are lower than previous value but must still be higher than capacity recorded in the
status field of the claim.
More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources
Expand Down Expand Up @@ -8436,6 +8451,24 @@ spec:
description: Kubelet's generated CSRs will
be addressed to this signer.
type: string
userAnnotations:
additionalProperties:
type: string
description: |-
userAnnotations allow pod authors to pass additional information to
the signer implementation. Kubernetes does not restrict or validate this
metadata in any way.

These values are copied verbatim into the `spec.unverifiedUserAnnotations` field of
the PodCertificateRequest objects that Kubelet creates.

Entries are subject to the same validation as object metadata annotations,
with the addition that all keys must be domain-prefixed. No restrictions
are placed on values, except an overall size limitation on the entire field.

Signers should document the keys and values they support. Signers should
deny requests that contain keys they do not recognize.
type: object
required:
- keyType
- signerName
Expand Down Expand Up @@ -8860,6 +8893,42 @@ spec:
x-kubernetes-list-map-keys:
- name
x-kubernetes-list-type: map
workloadRef:
description: |-
WorkloadRef provides a reference to the Workload object that this Pod belongs to.
This field is used by the scheduler to identify the PodGroup and apply the
correct group scheduling policies. The Workload object referenced
by this field may not exist at the time the Pod is created.
This field is immutable, but a Workload object with the same name
may be recreated with different policies. Doing this during pod scheduling
may result in the placement not conforming to the expected policies.
properties:
name:
description: |-
Name defines the name of the Workload object this Pod belongs to.
Workload must be in the same namespace as the Pod.
If it doesn't match any existing Workload, the Pod will remain unschedulable
until a Workload object is created and observed by the kube-scheduler.
It must be a DNS subdomain.
type: string
podGroup:
description: |-
PodGroup is the name of the PodGroup within the Workload that this Pod
belongs to. If it doesn't match any existing PodGroup within the Workload,
the Pod will remain unschedulable until the Workload object is recreated
and observed by the kube-scheduler. It must be a DNS label.
type: string
podGroupReplicaKey:
description: |-
PodGroupReplicaKey specifies the replica key of the PodGroup to which this
Pod belongs. It is used to distinguish pods belonging to different replicas
of the same pod group. The pod group policy is applied separately to each replica.
When set, it must be a DNS label.
type: string
required:
- name
- podGroup
type: object
required:
- containers
type: object
Expand Down
12 changes: 11 additions & 1 deletion internal/api/v1alpha1/access_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,17 @@ type AccessConfig struct {
MaxDuration string `json:"maxDuration"`

// AccessCommand is used to describe to the user how they can make use of their temporary access.
// The AccessCommand can reference data from a Pod ObjectMeta.
//
// The string is rendered as a Go text/template with the following variables available:
//
// - `{{ .Metadata }}`: the target Pod's ObjectMeta (e.g. `{{ .Metadata.Name }}`,
// `{{ .Metadata.Namespace }}`).
// - `{{ .ClientKubeContext }}`: the kubeconfig context the request was created in,
// populated automatically by `ozctl`. May be the empty string if the request was
// applied as raw YAML or by an older `ozctl` that did not set the field. To be
// safe in either case, gate references with a conditional, e.g.:
//
// kubectl {{ if .ClientKubeContext }}--context {{ .ClientKubeContext }} {{ end }}exec -ti -n {{ .Metadata.Namespace }} {{ .Metadata.Name }} -- /bin/sh
//
// +kubebuilder:validation:Optional
// +kubebuilder:default:="kubectl exec -ti -n {{ .Metadata.Namespace }} {{ .Metadata.Name }} -- /bin/sh"
Expand Down
9 changes: 9 additions & 0 deletions internal/api/v1alpha1/exec_access_request_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ type ExecAccessRequestSpec struct {
//
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
Duration string `json:"duration,omitempty"`

// ClientKubeContext is the name of the kubeconfig context that the client (typically `ozctl`)
// was using when it created this request. The controller does not act on this value; it is
// surfaced to the `accessCommand` template as `{{ .ClientKubeContext }}` so the rendered
// command can include `--context <name>` and target the same cluster the request was created
// in. Populated automatically by `ozctl`; safe to omit when applying YAML directly.
//
// +kubebuilder:validation:Optional
ClientKubeContext string `json:"clientKubeContext,omitempty"`
}

// ExecAccessRequestStatus defines the observed state of ExecAccessRequest
Expand Down
9 changes: 9 additions & 0 deletions internal/api/v1alpha1/pod_access_request_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ type PodAccessRequestSpec struct {
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Pattern="^[0-9]+(s|m|h)$"
Duration string `json:"duration,omitempty"`

// ClientKubeContext is the name of the kubeconfig context that the client (typically `ozctl`)
// was using when it created this request. The controller does not act on this value; it is
// surfaced to the `accessCommand` template as `{{ .ClientKubeContext }}` so the rendered
// command can include `--context <name>` and target the same cluster the request was created
// in. Populated automatically by `ozctl`; safe to omit when applying YAML directly.
//
// +kubebuilder:validation:Optional
ClientKubeContext string `json:"clientKubeContext,omitempty"`
}

// PodAccessRequestStatus defines the observed state of AccessRequest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ func (b *ExecAccessBuilder) CreateAccessResources(
return statusString, err
}

accessString, err := bldutil.CreateAccessCommand(execTmpl.Spec.AccessConfig.AccessCommand, targetPod.ObjectMeta)
accessString, err := bldutil.CreateAccessCommand(
execTmpl.Spec.AccessConfig.AccessCommand,
targetPod.ObjectMeta,
execReq.Spec.ClientKubeContext,
)
if err != nil {
return "", err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ func (b *PodAccessBuilder) CreateAccessResources(
return statusString, err
}

accessString, err := bldutil.CreateAccessCommand(podTmpl.Spec.AccessConfig.AccessCommand, pod.ObjectMeta)
accessString, err := bldutil.CreateAccessCommand(
podTmpl.Spec.AccessConfig.AccessCommand,
pod.ObjectMeta,
podReq.Spec.ClientKubeContext,
)
if err != nil {
return "", err
}
Expand Down
25 changes: 18 additions & 7 deletions internal/builders/utils/access_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,32 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// CreateAccessCommand templates an access command string,
// evaluates data from a pod.ObjectMeta
func CreateAccessCommand(cmdString string, resource metav1.ObjectMeta) (string, error) {
type md struct {
Metadata metav1.ObjectMeta
// CreateAccessCommand templates an access command string. The template can
// reference `{{ .Metadata }}` (the target pod's ObjectMeta) and
// `{{ .ClientKubeContext }}` (the kubeconfig context the request was created
// in, populated by `ozctl`; empty string when the request was applied as raw
// YAML).
func CreateAccessCommand(
cmdString string,
resource metav1.ObjectMeta,
clientKubeContext string,
) (string, error) {
type data struct {
Metadata metav1.ObjectMeta
ClientKubeContext string
}
d := data{
Metadata: resource,
ClientKubeContext: clientKubeContext,
}
m := md{resource}

tmpl, err := template.New("accessCommand").Parse(cmdString)
if err != nil {
return "", err
}

var buf bytes.Buffer
if err := tmpl.Execute(&buf, m); err != nil {
if err := tmpl.Execute(&buf, d); err != nil {
return "", err
}
return buf.String(), nil
Expand Down
33 changes: 30 additions & 3 deletions internal/builders/utils/access_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import (

func TestCreateAccessCommand(t *testing.T) {
type args struct {
cmdString string
resource *v1alpha1.ExecAccessTemplate
cmdString string
resource *v1alpha1.ExecAccessTemplate
clientKubeContext string
}
tests := []struct {
name string
Expand All @@ -32,10 +33,36 @@ func TestCreateAccessCommand(t *testing.T) {
want: "kubectl exec -ti -n namespace podName -- /bin/sh",
wantErr: false,
},
{
name: "client kube context is interpolated",
args: args{
cmdString: "kubectl --context {{ .ClientKubeContext }} exec -ti -n {{ .Metadata.Namespace }} {{ .Metadata.Name }} -- /bin/sh",
resource: &v1alpha1.ExecAccessTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: "podName",
Namespace: "namespace",
},
},
clientKubeContext: "us1",
},
want: "kubectl --context us1 exec -ti -n namespace podName -- /bin/sh",
wantErr: false,
},
{
name: "empty client kube context renders as empty string",
args: args{
cmdString: "ctx=[{{ .ClientKubeContext }}]",
resource: &v1alpha1.ExecAccessTemplate{
ObjectMeta: metav1.ObjectMeta{Name: "p", Namespace: "n"},
},
},
want: "ctx=[]",
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CreateAccessCommand(tt.args.cmdString, tt.args.resource.ObjectMeta)
got, err := CreateAccessCommand(tt.args.cmdString, tt.args.resource.ObjectMeta, tt.args.clientKubeContext)
if (err != nil) != tt.wantErr {
t.Errorf("CreateAccessCommand() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
7 changes: 4 additions & 3 deletions internal/cmd/ozctl/cmd/create_exec_access_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@ var createExecAccessRequestCmd = &cobra.Command{
Namespace: namespace,
},
Spec: api.ExecAccessRequestSpec{
TemplateName: template,
Duration: duration,
TargetPod: targetPod,
TemplateName: template,
Duration: duration,
TargetPod: targetPod,
ClientKubeContext: getCurrentKubeContext(),
},
}

Expand Down
5 changes: 3 additions & 2 deletions internal/cmd/ozctl/cmd/create_pod_access_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ var createPodAccessRequestCmd = &cobra.Command{
Namespace: namespace,
},
Spec: api.PodAccessRequestSpec{
TemplateName: templateName,
Duration: duration,
TemplateName: templateName,
Duration: duration,
ClientKubeContext: getCurrentKubeContext(),
},
}

Expand Down
Loading