Skip to content

Commit

Permalink
adjust the provider to use the available service Account annotations …
Browse files Browse the repository at this point in the history
…instead of requiring it again in the SPC parameters
  • Loading branch information
wenzel-felix committed Feb 3, 2024
1 parent 2fc9b5f commit 8c472e0
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 23 deletions.
24 changes: 24 additions & 0 deletions charts/csi-secrets-store-provider-azure/templates/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,27 @@ rules:
verbs: ["get", "watch", "list"]
{{- end }}
{{- end }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ template "sscdpa.fullname" . }}-cluster-role-binding
{{ include "sscdpa.labels" . | indent 2 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ template "sscdpa.fullname" . }}-cluster-role
subjects:
- kind: ServiceAccount
name: csi-secrets-store-provider-azure
namespace: {{ .Release.Namespace }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ template "sscdpa.fullname" . }}-cluster-role
{{ include "sscdpa.labels" . | indent 2 }}
rules:
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get"]
26 changes: 26 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require (
golang.org/x/net v0.17.0
google.golang.org/grpc v1.59.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/client-go v0.25.3
k8s.io/component-base v0.25.3
k8s.io/klog/v2 v2.80.1
sigs.k8s.io/secrets-store-csi-driver v1.3.4
Expand All @@ -35,18 +36,32 @@ require (
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
Expand All @@ -62,10 +77,21 @@ require (
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/api v0.25.3 // indirect
k8s.io/apimachinery v0.25.3 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
64 changes: 64 additions & 0 deletions go.sum

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions pkg/provider/kuberneteshelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package provider

import (
"context"
"fmt"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sv1 "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
)

const (
// ServiceAccountClientID annotation
ServiceAccountClientID = "azure.workload.identity/client-id"
)

type KubernetesHelper struct {
nameSpace, svcAcc string
k8sClient k8sv1.CoreV1Interface
}

func NewKubernetesHelper(nameSpace, svcAcc string) KubernetesHelper {
k8sClient, err := getK8sClient()
if err != nil {
panic(err)
}

return KubernetesHelper{
nameSpace: nameSpace,
svcAcc: svcAcc,
k8sClient: k8sClient,
}
}

func (k KubernetesHelper) GetServiceAccountClientID() (string, error) {
serviceAccount, err := k.k8sClient.ServiceAccounts(k.nameSpace).Get(context.Background(), k.svcAcc, metav1.GetOptions{})
if err != nil {
return "", fmt.Errorf("failed to get service account %s in namespace %s, error: %w", k.svcAcc, k.nameSpace, err)
}
clientID, ok := serviceAccount.Annotations[ServiceAccountClientID]
if !ok {
return "", fmt.Errorf("clientID not found in service account %s in namespace %s", k.svcAcc, k.nameSpace)
}
return clientID, nil
}

func getK8sClient() (k8sv1.CoreV1Interface, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("failed to get in cluster config, error: %w", err)
}
k8sClient, err := k8sv1.NewForConfig(config)
if err != nil {
panic(err)
}
return k8sClient, nil
}
7 changes: 6 additions & 1 deletion pkg/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (p *provider) GetSecretsStoreObjectContent(ctx context.Context, attrib, sec
cloudEnvFileName := types.GetCloudEnvFileName(attrib)
podName := types.GetPodName(attrib)
podNamespace := types.GetPodNamespace(attrib)
saName := types.GetServiceAccountName(attrib)

usePodIdentity, err := types.GetUsePodIdentity(attrib)
if err != nil {
Expand All @@ -134,7 +135,11 @@ func (p *provider) GetSecretsStoreObjectContent(ctx context.Context, attrib, sec
}

// attributes for workload identity
workloadIdentityClientID := types.GetClientID(attrib)
kubernetesHelper := NewKubernetesHelper(podNamespace, saName)
workloadIdentityClientID, err := kubernetesHelper.GetServiceAccountClientID()
if err != nil {
return nil, fmt.Errorf("failed to get service account client id, error: %w", err)
}
saTokens := types.GetServiceAccountTokens(attrib)

if keyvaultName == "" {
Expand Down
10 changes: 5 additions & 5 deletions pkg/provider/types/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,16 @@ func GetPodNamespace(parameters map[string]string) string {
return strings.TrimSpace(parameters[CSIAttributePodNamespace])
}

// GetClientID returns the client ID
func GetClientID(parameters map[string]string) string {
return strings.TrimSpace(parameters[ClientIDParameter])
}

// GetServiceAccountTokens returns the service account tokens
func GetServiceAccountTokens(parameters map[string]string) string {
return strings.TrimSpace(parameters[CSIAttributeServiceAccountTokens])
}

// GetServiceAccountName returns the service account name
func GetServiceAccountName(parameters map[string]string) string {
return strings.TrimSpace(parameters[CSIAttributeServiceAccountName])
}

// GetObjects returns the key vault objects
func GetObjects(parameters map[string]string) string {
return strings.TrimSpace(parameters[ObjectsParameter])
Expand Down
24 changes: 12 additions & 12 deletions pkg/provider/types/parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ func TestGetPodNamespace(t *testing.T) {
}
}

func TestGetClientID(t *testing.T) {
func TestGetServiceAccountTokens(t *testing.T) {
tests := []struct {
name string
parameters map[string]string
Expand All @@ -447,37 +447,37 @@ func TestGetClientID(t *testing.T) {
{
name: "empty",
parameters: map[string]string{
"clientID": "",
CSIAttributeServiceAccountTokens: "",
},
expected: "",
},
{
name: "not empty",
parameters: map[string]string{
"clientID": "test",
CSIAttributeServiceAccountTokens: "test",
},
expected: "test",
},
{
name: "trim spaces",
parameters: map[string]string{
"clientID": " test ",
CSIAttributeServiceAccountTokens: " test ",
},
expected: "test",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := GetClientID(test.parameters)
actual := GetServiceAccountTokens(test.parameters)
if actual != test.expected {
t.Errorf("GetClientID() = %v, expected %v", actual, test.expected)
t.Errorf("GetServiceAccountTokens() = %v, expected %v", actual, test.expected)
}
})
}
}

func TestGetServiceAccountTokens(t *testing.T) {
func TestGetServiceAccountName(t *testing.T) {
tests := []struct {
name string
parameters map[string]string
Expand All @@ -486,31 +486,31 @@ func TestGetServiceAccountTokens(t *testing.T) {
{
name: "empty",
parameters: map[string]string{
CSIAttributeServiceAccountTokens: "",
CSIAttributeServiceAccountName: "",
},
expected: "",
},
{
name: "not empty",
parameters: map[string]string{
CSIAttributeServiceAccountTokens: "test",
CSIAttributeServiceAccountName: "test",
},
expected: "test",
},
{
name: "trim spaces",
parameters: map[string]string{
CSIAttributeServiceAccountTokens: " test ",
CSIAttributeServiceAccountName: " test ",
},
expected: "test",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := GetServiceAccountTokens(test.parameters)
actual := GetServiceAccountName(test.parameters)
if actual != test.expected {
t.Errorf("GetServiceAccountTokens() = %v, expected %v", actual, test.expected)
t.Errorf("GetServiceAccountName() = %v, expected %v", actual, test.expected)
}
})
}
Expand Down
1 change: 1 addition & 0 deletions pkg/provider/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
CSIAttributePodName = "csi.storage.k8s.io/pod.name"
CSIAttributePodNamespace = "csi.storage.k8s.io/pod.namespace"
CSIAttributeServiceAccountTokens = "csi.storage.k8s.io/serviceAccount.tokens" // nolint
CSIAttributeServiceAccountName = "csi.storage.k8s.io/serviceAccount.name"

// KeyVaultNameParameter is the name of the key vault name parameter
KeyVaultNameParameter = "keyvaultName"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ spec:
provider: azure
parameters:
usePodIdentity: "false" # set to true for pod identity access mode
clientID: "<client id of the Azure AD Application or user-assigned managed identity to use for workload identity>"
keyvaultName: "kvname"
cloudName: "" # [OPTIONAL for Azure] if not provided, azure environment will default to AzurePublicCloud
objects: |
Expand Down Expand Up @@ -172,10 +171,12 @@ az identity federated-credential create \

### 4. Deploy your secretproviderclass and application

Set the `clientID` in the `SecretProviderClass` to the client ID of the AAD application or user-assigned managed identity.
Set the `azure.workload.identity/client-id` annotation in the `ServiceAccount` of your pod to the client ID of the AAD application or user-assigned managed identity.

```yaml
clientID: "${APPLICATION_OR_MANAGED_IDENTITY_CLIENT_ID}"
metadata:
annoations:
azure.workload.identity/client-id: "${APPLICATION_OR_MANAGED_IDENTITY_CLIENT_ID}"
```

## Pros
Expand Down
2 changes: 0 additions & 2 deletions website/content/en/getting-started/usage/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ To provide identity to access Key Vault, refer to the following [section](#provi
usePodIdentity: "false" # [OPTIONAL] if not provided, will default to "false"
useVMManagedIdentity: "false" # [OPTIONAL available for version > 0.0.4] if not provided, will default to "false"
userAssignedIdentityID: "client_id" # [OPTIONAL available for version > 0.0.4] use the client id to specify which user assigned managed identity to use. If using a user assigned identity as the VM's managed identity, then specify the identity's client id. If empty, then defaults to use the system assigned identity on the VM
clientID: "client_id" # [OPTIONAL available for version > 1.1.0] client id of the Azure AD Application or managed identity to use for workload identity
keyvaultName: "kvname" # the name of the KeyVault
cloudName: "" # [OPTIONAL available for version > 0.0.4] if not provided, azure environment will default to AzurePublicCloud
cloudEnvFileName: "" # [OPTIONAL available for version > 0.0.7] use to define path to file for populating azure environment
Expand Down Expand Up @@ -69,7 +68,6 @@ To provide identity to access Key Vault, refer to the following [section](#provi
| usePodIdentity | no | set to true for using aad-pod-identity to access keyvault | "false" |
| useVMManagedIdentity | no | [__*available for version > 0.0.4*__] specify access mode to enable use of User-assigned managed identity | "false" |
| userAssignedIdentityID | no | [__*available for version > 0.0.4*__] the user assigned identity ID is required for User-assigned Managed Identity mode | "" |
| clientID | no | [__*available for version > 1.1.0*__] client id of the Azure AD Application or managed identity to use for workload identity | "" |
| keyvaultName | yes | name of a Key Vault instance | "" |
| cloudName | no | [__*available for version > 0.0.4*__] name of the azure cloud based on azure go sdk (AzurePublicCloud, AzureUSGovernmentCloud, AzureChinaCloud, AzureGermanCloud, AzureStackCloud) | "" |
| cloudEnvFileName | no | [__*available for version > 0.0.7*__] path to the file to be used while populating the Azure Environment (required if target cloud is AzureStackCloud). More details [here](../../configurations/custom-environments). | "" |
Expand Down

0 comments on commit 8c472e0

Please sign in to comment.