func()

in pkg/provider/provider.go [117:266]


func (p *provider) GetSecretsStoreObjectContent(ctx context.Context, attrib, secrets map[string]string, defaultFilePermission os.FileMode) ([]types.SecretFile, error) {
	keyvaultName := types.GetKeyVaultName(attrib)
	cloudName := types.GetCloudName(attrib)
	userAssignedIdentityID := types.GetUserAssignedIdentityID(attrib)
	tenantID := types.GetTenantID(attrib)
	cloudEnvFileName := types.GetCloudEnvFileName(attrib)
	podName := types.GetPodName(attrib)
	podNamespace := types.GetPodNamespace(attrib)

	usePodIdentity, err := types.GetUsePodIdentity(attrib)
	if err != nil {
		return nil, fmt.Errorf("failed to parse usePodIdentity flag, error: %w", err)
	}
	useVMManagedIdentity, err := types.GetUseVMManagedIdentity(attrib)
	if err != nil {
		return nil, fmt.Errorf("failed to parse useVMManagedIdentity flag, error: %w", err)
	}

	// attributes for workload identity
	workloadIdentityClientID := types.GetClientID(attrib)
	saTokens := types.GetServiceAccountTokens(attrib)

	if keyvaultName == "" {
		return nil, fmt.Errorf("keyvaultName is not set")
	}
	if tenantID == "" {
		return nil, fmt.Errorf("tenantId is not set")
	}

	err = setAzureEnvironmentFilePath(cloudEnvFileName)
	if err != nil {
		return nil, fmt.Errorf("failed to set AZURE_ENVIRONMENT_FILEPATH env to %s, error %w", cloudEnvFileName, err)
	}
	azureCloudEnv, err := p.parseAzureEnvironment(cloudName)
	if err != nil {
		return nil, fmt.Errorf("cloudName %s is not valid, error: %w", cloudName, err)
	}

	// parse bound service account tokens for workload identity only if the clientID is set
	var workloadIdentityToken string
	if workloadIdentityClientID != "" {
		if workloadIdentityToken, err = auth.ParseServiceAccountToken(saTokens); err != nil {
			return nil, fmt.Errorf("failed to parse workload identity tokens, error: %w", err)
		}
	}

	authConfig, err := auth.NewConfig(usePodIdentity, useVMManagedIdentity, userAssignedIdentityID, workloadIdentityClientID, workloadIdentityToken, secrets)
	if err != nil {
		return nil, fmt.Errorf("failed to create auth config, error: %w", err)
	}

	mc := &mountConfig{
		keyvaultName:          keyvaultName,
		azureCloudEnvironment: azureCloudEnv,
		authConfig:            authConfig,
		tenantID:              tenantID,
		podName:               podName,
		podNamespace:          podNamespace,
	}

	objectsStrings := types.GetObjects(attrib)
	if objectsStrings == "" {
		return nil, fmt.Errorf("objects is not set")
	}
	klog.V(2).InfoS("objects string defined in secret provider class", "objects", objectsStrings, "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})

	objects, err := types.GetObjectsArray(objectsStrings)
	if err != nil {
		return nil, fmt.Errorf("failed to yaml unmarshal objects, error: %w", err)
	}
	klog.V(2).InfoS("unmarshaled objects yaml array", "objectsArray", objects.Array, "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})

	keyVaultObjects := []types.KeyVaultObject{}
	for i, object := range objects.Array {
		var keyVaultObject types.KeyVaultObject
		err = yaml.Unmarshal([]byte(object), &keyVaultObject)
		if err != nil {
			return nil, fmt.Errorf("unmarshal failed for keyVaultObjects at index %d, error: %w", i, err)
		}
		// remove whitespace from all fields in keyVaultObject
		formatKeyVaultObject(&keyVaultObject)

		if err = validate(keyVaultObject); err != nil {
			return nil, wrapObjectTypeError(err, keyVaultObject.ObjectType, keyVaultObject.ObjectName, keyVaultObject.ObjectVersion)
		}

		keyVaultObjects = append(keyVaultObjects, keyVaultObject)
	}

	klog.V(5).InfoS("unmarshaled key vault objects", "keyVaultObjects", keyVaultObjects, "count", len(keyVaultObjects), "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})

	if len(keyVaultObjects) == 0 {
		return nil, nil
	}

	vaultURL, err := mc.getVaultURL()
	if err != nil {
		return nil, errors.Wrap(err, "failed to get vault")
	}
	klog.V(2).InfoS("vault url", "vaultName", mc.keyvaultName, "vaultURL", *vaultURL, "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})

	// the keyvault name is per SPC and we don't need to recreate the client for every single keyvault object defined
	kvClient, err := mc.initializeKvClient(*vaultURL)
	if err != nil {
		return nil, errors.Wrap(err, "failed to get keyvault client")
	}

	files := []types.SecretFile{}
	for _, keyVaultObject := range keyVaultObjects {
		klog.V(5).InfoS("fetching object from key vault", "objectName", keyVaultObject.ObjectName, "objectType", keyVaultObject.ObjectType, "keyvault", mc.keyvaultName, "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})

		resolvedKvObjects, err := p.resolveObjectVersions(ctx, kvClient, keyVaultObject)
		if err != nil {
			return nil, err
		}

		for _, resolvedKvObject := range resolvedKvObjects {
			// fetch the object from Key Vault
			result, err := p.getKeyVaultObjectContent(ctx, kvClient, resolvedKvObject)
			if err != nil {
				return nil, err
			}

			for idx := range result {
				r := result[idx]
				objectContent, err := getContentBytes(r.content, resolvedKvObject.ObjectType, resolvedKvObject.ObjectEncoding)
				if err != nil {
					return nil, err
				}

				// objectUID is a unique identifier in the format <object type>/<object name>
				// This is the object id the user sees in the SecretProviderClassPodStatus
				objectUID := resolvedKvObject.GetObjectUID()
				file := types.SecretFile{
					Path:    resolvedKvObject.GetFileName() + r.fileNameSuffix,
					Content: objectContent,
					UID:     objectUID,
					Version: r.version,
				}
				// the validity of file permission is already checked in the validate function above
				file.FileMode, _ = resolvedKvObject.GetFilePermission(defaultFilePermission)

				files = append(files, file)
				klog.V(5).InfoS("added file to the gRPC response", "file", file.Path, "pod", klog.ObjectRef{Namespace: podNamespace, Name: podName})
			}
		}
	}

	return files, nil
}