Use ServiceAccountName for impersonation
Drop the ServiceAccount field in favour of ServiceAccountName to prevent privilege escalation in multi-tenancy environments. Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>
This commit is contained in:
parent
41a8a7eaf9
commit
0c9170241f
|
@ -66,9 +66,10 @@ type KustomizationSpec struct {
|
|||
// +optional
|
||||
HealthChecks []CrossNamespaceObjectReference `json:"healthChecks,omitempty"`
|
||||
|
||||
// The Kubernetes service account used for applying the kustomization.
|
||||
// The name of the Kubernetes service account to impersonate
|
||||
// when reconciling this Kustomization.
|
||||
// +optional
|
||||
ServiceAccount *ServiceAccount `json:"serviceAccount,omitempty"`
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
||||
|
||||
// Reference of the source where the kustomization file is.
|
||||
// +required
|
||||
|
@ -99,17 +100,6 @@ type KustomizationSpec struct {
|
|||
Validation string `json:"validation,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceAccount defines a reference to a Kubernetes service account.
|
||||
type ServiceAccount struct {
|
||||
// Name is the name of the service account being referenced.
|
||||
// +required
|
||||
Name string `json:"name"`
|
||||
|
||||
// Namespace is the namespace of the service account being referenced.
|
||||
// +required
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// Decryption defines how decryption is handled for Kubernetes manifests.
|
||||
type Decryption struct {
|
||||
// Provider is the name of the decryption engine.
|
||||
|
|
|
@ -176,11 +176,6 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
|
|||
*out = make([]CrossNamespaceObjectReference, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ServiceAccount != nil {
|
||||
in, out := &in.ServiceAccount, &out.ServiceAccount
|
||||
*out = new(ServiceAccount)
|
||||
**out = **in
|
||||
}
|
||||
out.SourceRef = in.SourceRef
|
||||
if in.Timeout != nil {
|
||||
in, out := &in.Timeout, &out.Timeout
|
||||
|
@ -227,21 +222,6 @@ func (in *KustomizationStatus) DeepCopy() *KustomizationStatus {
|
|||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ServiceAccount) DeepCopyInto(out *ServiceAccount) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceAccount.
|
||||
func (in *ServiceAccount) DeepCopy() *ServiceAccount {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ServiceAccount)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Snapshot) DeepCopyInto(out *Snapshot) {
|
||||
*out = *in
|
||||
|
|
|
@ -140,21 +140,10 @@ spec:
|
|||
prune:
|
||||
description: Prune enables garbage collection.
|
||||
type: boolean
|
||||
serviceAccount:
|
||||
description: The Kubernetes service account used for applying the
|
||||
kustomization.
|
||||
properties:
|
||||
name:
|
||||
description: Name is the name of the service account being referenced.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace is the namespace of the service account
|
||||
being referenced.
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- namespace
|
||||
type: object
|
||||
serviceAccountName:
|
||||
description: The name of the Kubernetes service account to impersonate
|
||||
when reconciling this Kustomization.
|
||||
type: string
|
||||
sourceRef:
|
||||
description: Reference of the source where the kustomization file
|
||||
is.
|
||||
|
|
|
@ -645,8 +645,8 @@ func (r *KustomizationReconciler) getKubeConfig(kustomization kustomizev1.Kustom
|
|||
|
||||
func (r *KustomizationReconciler) getServiceAccountToken(kustomization kustomizev1.Kustomization) (string, error) {
|
||||
namespacedName := types.NamespacedName{
|
||||
Namespace: kustomization.Spec.ServiceAccount.Namespace,
|
||||
Name: kustomization.Spec.ServiceAccount.Name,
|
||||
Namespace: kustomization.Namespace,
|
||||
Name: kustomization.Spec.ServiceAccountName,
|
||||
}
|
||||
|
||||
var serviceAccount corev1.ServiceAccount
|
||||
|
@ -656,8 +656,8 @@ func (r *KustomizationReconciler) getServiceAccountToken(kustomization kustomize
|
|||
}
|
||||
|
||||
secretName := types.NamespacedName{
|
||||
Namespace: kustomization.Spec.ServiceAccount.Namespace,
|
||||
Name: kustomization.Spec.ServiceAccount.Name,
|
||||
Namespace: kustomization.Namespace,
|
||||
Name: kustomization.Spec.ServiceAccountName,
|
||||
}
|
||||
|
||||
for _, secret := range serviceAccount.Secrets {
|
||||
|
@ -700,7 +700,7 @@ func (r *KustomizationReconciler) apply(kustomization kustomizev1.Kustomization,
|
|||
cmd = fmt.Sprintf("%s --kubeconfig=%s", cmd, kubeConfig)
|
||||
} else {
|
||||
// impersonate SA
|
||||
if kustomization.Spec.ServiceAccount != nil {
|
||||
if kustomization.Spec.ServiceAccountName != "" {
|
||||
saToken, err := r.getServiceAccountToken(kustomization)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("service account impersonation failed: %w", err)
|
||||
|
|
|
@ -163,16 +163,15 @@ bool
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccount</code><br>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1beta1.ServiceAccount">
|
||||
ServiceAccount
|
||||
</a>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>The Kubernetes service account used for applying the kustomization.</p>
|
||||
<p>The name of the Kubernetes service account to impersonate
|
||||
when reconciling this Kustomization.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -596,16 +595,15 @@ bool
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>serviceAccount</code><br>
|
||||
<code>serviceAccountName</code><br>
|
||||
<em>
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1beta1.ServiceAccount">
|
||||
ServiceAccount
|
||||
</a>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>The Kubernetes service account used for applying the kustomization.</p>
|
||||
<p>The name of the Kubernetes service account to impersonate
|
||||
when reconciling this Kustomization.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -779,49 +777,6 @@ Snapshot
|
|||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="kustomize.toolkit.fluxcd.io/v1beta1.ServiceAccount">ServiceAccount
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kustomize.toolkit.fluxcd.io/v1beta1.KustomizationSpec">KustomizationSpec</a>)
|
||||
</p>
|
||||
<p>ServiceAccount defines a reference to a Kubernetes service account.</p>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>name</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Name is the name of the service account being referenced.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>namespace</code><br>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Namespace is the namespace of the service account being referenced.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<h3 id="kustomize.toolkit.fluxcd.io/v1beta1.Snapshot">Snapshot
|
||||
</h3>
|
||||
<p>
|
||||
|
|
|
@ -34,11 +34,12 @@ of the frontend app was deployed and if the deployment is healthy, no matter the
|
|||
The reconciliation process can be defined with a Kubernetes custom resource
|
||||
that describes a pipeline such as:
|
||||
- **check** if depends-on conditions are meet
|
||||
- **fetch** manifests from Git repository X
|
||||
- **fetch** manifests from source-controller (Git repository or S3 bucket)
|
||||
- **generate** a kustomization if needed
|
||||
- **build** the manifest using kustomization X
|
||||
- **decrypt** Kubernetes secrets using Mozilla SOPS
|
||||
- **validate** the resulting objects
|
||||
- **impersonate** Kubernetes account
|
||||
- **apply** the objects
|
||||
- **prune** the objects removed from source
|
||||
- **verify** the deployment status
|
||||
|
@ -76,6 +77,7 @@ The API design of the controller can be found at [kustomize.toolkit.fluxcd.io/v1
|
|||
| Plain Kubernetes manifests sync | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Kustomize build sync | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Garbage collection | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Secrets decryption | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| Container image updates | :x: | :heavy_check_mark: |
|
||||
| Generate manifests with shell scripts | :x: | :heavy_check_mark: |
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ of Kubernetes objects generated with Kustomize.
|
|||
+ [Health assessment](kustomization.md#health-assessment)
|
||||
+ [Kustomization dependencies](kustomization.md#kustomization-dependencies)
|
||||
+ [Role-based access control](kustomization.md#role-based-access-control)
|
||||
+ [Targeting remote clusters](kustomization.md#remote-clusters--cluster-api)
|
||||
+ [Secrets decryption](kustomization.md#secrets-decryption)
|
||||
+ [Status](kustomization.md#status)
|
||||
|
||||
|
|
|
@ -42,9 +42,10 @@ type KustomizationSpec struct {
|
|||
// +optional
|
||||
HealthChecks []CrossNamespaceObjectReference `json:"healthChecks,omitempty"`
|
||||
|
||||
// The Kubernetes service account used for applying the kustomization.
|
||||
// The name of the Kubernetes service account to impersonate
|
||||
// when reconciling this Kustomization.
|
||||
// +optional
|
||||
ServiceAccount *ServiceAccount `json:"serviceAccount,omitempty"`
|
||||
ServiceAccountName string `json:"serviceAccountName,omitempty"`
|
||||
|
||||
// Reference of the source where the kustomization file is.
|
||||
// +required
|
||||
|
@ -217,7 +218,7 @@ file is automatically generated for all the Kubernetes manifests
|
|||
in the `spec.path` and sub-directories. This expects all YAML files present under that path to be valid kubernetes manifests
|
||||
and needs non-kubernetes ones to be excluded using `.sourceignore` file or `spec.ignore` on `GitRepository` object.
|
||||
|
||||
Example of excluding gitlab ci workflows and sops rules creation files:
|
||||
Example of excluding CI workflows and SOPS config files:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||
|
@ -230,6 +231,7 @@ spec:
|
|||
url: https://github.com/stefanprodan/podinfo
|
||||
ignore: |
|
||||
.git/
|
||||
.github/
|
||||
.sops.yaml
|
||||
.gitlab-ci.yml
|
||||
```
|
||||
|
@ -514,11 +516,9 @@ metadata:
|
|||
name: backend
|
||||
namespace: webapp
|
||||
spec:
|
||||
serviceAccountName: webapp-reconciler
|
||||
dependsOn:
|
||||
- name: common
|
||||
serviceAccount:
|
||||
name: webapp-reconciler
|
||||
namespace: webapp
|
||||
interval: 5m
|
||||
path: "./webapp/backend/"
|
||||
prune: true
|
||||
|
|
Loading…
Reference in New Issue