Skip to content

Commit

Permalink
Cosmos DB Output Binding - Authentication tests (#1373)
Browse files Browse the repository at this point in the history
* Adds CosmosDB Binding authentication tests

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* Enable Cosmos DB Binding Conformance test

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* Initial cosmosdb binding certification plan WIP

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* Go mod tidy

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* Update library and go mod tidy

Signed-off-by: GitHub <noreply@github.com>
Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* make modtidy-all

Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>

* CosmosDB Binding test plan details

Signed-off-by: Bernd Verst <4535280+berndverst@users.noreply.github.com>
  • Loading branch information
berndverst authored Dec 13, 2021
1 parent 72bae26 commit 9dbdaee
Show file tree
Hide file tree
Showing 23 changed files with 2,143 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module cosmosDb 'conf-test-azure-cosmosdb.bicep' = {
}
}

module eventGridTopic 'conf-test-azure-eventGrid.bicep' = {
module eventGridTopic 'conf-test-azure-eventgrid.bicep' = {
name: eventGridTopicName
scope: resourceGroup(confTestRg.name)
params: {
Expand All @@ -81,7 +81,7 @@ module eventGridTopic 'conf-test-azure-eventGrid.bicep' = {
}
}

module eventHubsNamespace 'conf-test-azure-eventHubs.bicep' = {
module eventHubsNamespace 'conf-test-azure-eventhubs.bicep' = {
name: eventHubsNamespaceName
scope: resourceGroup(confTestRg.name)
params: {
Expand All @@ -99,7 +99,7 @@ module iotHub 'conf-test-azure-iothub.bicep' = {
}
}

module keyVault 'conf-test-azure-keyVault.bicep' = {
module keyVault 'conf-test-azure-keyvault.bicep' = {
name: keyVaultName
scope: resourceGroup(confTestRg.name)
params: {
Expand Down
33 changes: 28 additions & 5 deletions .github/infrastructure/conformance/azure/setup-azure-conf-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ echo "CREDENTIALS_PATH=${CREDENTIALS_PATH}"
# Constant environment variable names defined by tests or GitHub workflow
ACR_VAR_NAME="AzureContainerRegistryName"

CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_SECRET_VAR_NAME="AzureCertificationServicePrincipalClientSecret"
CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_ID_VAR_NAME="AzureCertificationServicePrincipalClientId"
CERTIFICATION_TENANT_ID_VAR_NAME="AzureCertificationTenantId"

COSMOS_DB_VAR_NAME="AzureCosmosDB"
COSMOS_DB_COLLECTION_VAR_NAME="AzureCosmosDBCollection"
COSMOS_DB_MASTER_KEY_VAR_NAME="AzureCosmosDBMasterKey"
Expand Down Expand Up @@ -221,8 +225,8 @@ echo "Created Service Principal for cert auth: ${CERT_AUTH_SP_NAME}"

if [[ -n ${CREDENTIALS_PATH} ]]; then
SDK_AUTH_SP_INFO="$(cat ${CREDENTIALS_PATH})"
SDK_AUTH_SP_APPID="$(echo "${SDK_AUTH_SP_INFO}" | grep 'clientId' | sed -E 's/(.*clientId\"\: \")|\".*//g')"
SDK_AUTH_SP_CLIENT_SECRET="$(echo "${SDK_AUTH_SP_INFO}" | grep 'clientSecret' | sed -E 's/(.*clientSecret\"\: \")|\".*//g')"
SDK_AUTH_SP_APPID="$(echo "${SDK_AUTH_SP_INFO}" | grep 'clientId' | sed -E 's/(.*clientId\"\: \")|\",//g')"
SDK_AUTH_SP_CLIENT_SECRET="$(echo "${SDK_AUTH_SP_INFO}" | grep 'clientSecret' | sed -E 's/(.*clientSecret\"\: \")|\",//g')"
if [[ -z ${SDK_AUTH_SP_APPID} || -z ${SDK_AUTH_SP_CLIENT_SECRET} ]]; then
echo "Invalid credentials JSON file. Contents should match output of 'az ad sp create-for-rbac' command."
exit 1
Expand Down Expand Up @@ -601,14 +605,33 @@ IOT_HUB_PUBSUB_CONSUMER_GROUP_NAME="$(basename ${IOT_HUB_PUBSUB_CONSUMER_GROUP_F
echo export ${IOT_HUB_PUBSUB_CONSUMER_GROUP_VAR_NAME}=\"${IOT_HUB_PUBSUB_CONSUMER_GROUP_NAME}\" >> "${ENV_CONFIG_FILENAME}"
az keyvault secret set --name "${IOT_HUB_PUBSUB_CONSUMER_GROUP_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${IOT_HUB_PUBSUB_CONSUMER_GROUP_NAME}"

# ---------------------------------------
# Populate Managed Identity Test settings
# ---------------------------------------
# -------------------------------------------------------------
# CERTIFICATION TESTS: Populate Managed Identity Test settings
# -------------------------------------------------------------
echo "Configuring Azure Container Registry for Managed Identity Certification tests ..."
echo export ${ACR_VAR_NAME}=\"${AZURE_CONTAINER_REGISTRY_NAME}\" >> "${ENV_CONFIG_FILENAME}"
az keyvault secret set --name "${ACR_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${AZURE_CONTAINER_REGISTRY_NAME}"


# -----------------------------------------------------------------------
# CERTIFICATION TESTS: Create service principal and grant resource access
# ------------------------------------------------------------------------
CERTIFICATION_SPAUTH_SP_NAME="${PREFIX}-certification-spauth-conf-test-sp"
{ read CERTIFICATION_SPAUTH_SP_CLIENT_ID ; read CERTIFICATION_SPAUTH_SP_CLIENT_SECRET ; } < <(az ad sp create-for-rbac --name ${CERTIFICATION_SPAUTH_SP_NAME} --skip-assignment --years 1 --query "[appId,password]" -otsv)
CERTIFICATION_SPAUTH_SP_PRINCIPAL_ID="$(az ad sp list --display-name "${CERTIFICATION_SPAUTH_SP_NAME}" --query "[].objectId" --output tsv)"

# Give the service principal used for certification test access to the relevant data plane resources
az cosmosdb sql role assignment create --account-name ${COSMOS_DB_NAME} --resource-group "${RESOURCE_GROUP_NAME}" --role-definition-name "Cosmos DB Built-in Data Contributor" --scope "/subscriptions/${SUB_ID}/resourceGroups/${RESOURCE_GROUP_NAME}/providers/Microsoft.DocumentDB/databaseAccounts/${COSMOS_DB_NAME}" --principal-id "${CERTIFICATION_SPAUTH_SP_PRINCIPAL_ID}"

# Now export the service principal information
CERTIFICATION_TENANT_ID="$(az ad sp list --display-name "${CERTIFICATION_SPAUTH_SP_NAME}" --query "[].appOwnerTenantId" --output tsv)"
echo export ${CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_ID_VAR_NAME}=\"${CERTIFICATION_SPAUTH_SP_CLIENT_ID}\" >> "${ENV_CONFIG_FILENAME}"
az keyvault secret set --name "${CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_ID_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${CERTIFICATION_SPAUTH_SP_CLIENT_ID}"
echo export ${CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_SECRET_VAR_NAME}=\"${CERTIFICATION_SPAUTH_SP_CLIENT_SECRET}\" >> "${ENV_CONFIG_FILENAME}"
az keyvault secret set --name "${CERTIFICATION_SERVICE_PRINCIPAL_CLIENT_SECRET_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${CERTIFICATION_SPAUTH_SP_CLIENT_SECRET}"
echo export ${CERTIFICATION_TENANT_ID_VAR_NAME}=\"${CERTIFICATION_TENANT_ID}\" >> "${ENV_CONFIG_FILENAME}"
az keyvault secret set --name "${CERTIFICATION_TENANT_ID_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${CERTIFICATION_TENANT_ID}"

# ---------------------------
# Display completion message
# ---------------------------
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/certification.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ jobs:
required-secrets: AzureSqlServerConnectionString
- component: bindings.azure.servicebusqueues
required-secrets: AzureServiceBusConnectionString
- component: bindings.azure.cosmosdb
required-secrets: AzureCosmosDBUrl,AzureCosmosDB,AzureCosmosDBCollection,AzureCosmosDBMasterKey,AzureCertificationTenantId,AzureCertificationServicePrincipalClientId,AzureCertificationServicePrincipalClientSecret
EOF
)
echo "::set-output name=cloud-components::$CRON_COMPONENTS"
Expand Down
2 changes: 1 addition & 1 deletion authentication/azure/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func NewEnvironmentSettings(resourceName string, values map[string]string) (Envi
es.Resource = azureEnv.ResourceIdentifiers.Storage
case "cosmosdb":
// Azure Cosmos DB (data plane)
es.Resource = "https://" + azureEnv.CosmosDBDNSSuffix
es.Resource = azureEnv.ResourceIdentifiers.CosmosDB
case "servicebus":
es.Resource = azureEnv.ResourceIdentifiers.ServiceBus
default:
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/Azure/azure-storage-blob-go v0.10.0
github.com/Azure/azure-storage-queue-go v0.0.0-20191125232315-636801874cdd
github.com/Azure/go-amqp v0.13.1
github.com/Azure/go-autorest/autorest v0.11.21
github.com/Azure/go-autorest/autorest v0.11.23
github.com/Azure/go-autorest/autorest/adal v0.9.16
github.com/Azure/go-autorest/autorest/azure/auth v0.5.8
github.com/DATA-DOG/go-sqlmock v1.5.0
Expand Down Expand Up @@ -128,7 +128,7 @@ require (
go.mongodb.org/mongo-driver v1.5.1
go.opencensus.io v0.22.5 // indirect
goji.io v2.0.2+incompatible // indirect
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
google.golang.org/api v0.32.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKn
github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
github.com/Azure/go-autorest/autorest v0.11.7/go.mod h1:V6p3pKZx1KKkJubbxnDWrzNhEIfOy/pTGasLqzHIPHs=
github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
github.com/Azure/go-autorest/autorest v0.11.21 h1:w77zY/9RnUAWcIQyDC0Fc89mCvwftR8F+zsR/OH6enk=
github.com/Azure/go-autorest/autorest v0.11.21/go.mod h1:Do/yuMSW/13ayUkcVREpsMHGG+MvV81uzSCFgYPj4tM=
github.com/Azure/go-autorest/autorest v0.11.23 h1:bRQWsW25/YkoxnIqXMPF94JW33qWDcrPMZ3bINaAruU=
github.com/Azure/go-autorest/autorest v0.11.23/go.mod h1:BAWYUWGPEtKPzjVkp0Q6an0MJcJDsoh5Z1BFAEFs4Xs=
github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
Expand Down Expand Up @@ -1302,8 +1302,8 @@ golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down
23 changes: 23 additions & 0 deletions tests/certification/bindings/azure/cosmosdb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Azure CosmosDB Binding certification testing

This project aims to test the Azure CosmosDB binding component under various conditions.

## Test plan

### Authentication tests

* Authenticate with Azure Active Directory using Service Principal Client Secret
* Authenticate with Master Key

### Other tests
- TODO: Verify data sent to output binding is written to Cosmos DB
- TODO: Expected failure for invalid partition key specified (Component Metadata Partition Key does not match Cosmos DB container)
- TODO: Expected failure for partition key missing from document
- TODO: Expected failure for `id` missing from document
- TODO: Graceful handling of connection resets / interruption (client connection only, not during Invoke/Create operation itself)

### Running the tests

This must be run in the GitHub Actions Workflow configured for test infrastructure setup.

If you have access to an Azure subscription you can run this locally on Mac or Linux after running `setup-azure-conf-test.sh` in `.github/infrastructure/conformance/azure` and then sourcing the generated bash rc file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: azure-cosmosdb-binding
namespace: default
spec:
type: bindings.azure.cosmosdb
version: v1
metadata:
- name: url
secretKeyRef:
name: AzureCosmosDBUrl
key: AzureCosmosDBUrl
- name: database
secretKeyRef:
name: AzureCosmosDB
key: AzureCosmosDB
- name: collection
secretKeyRef:
name: AzureCosmosDBCollection
key: AzureCosmosDBCollection
- name: partitionKey
value: partitionKey
- name: masterKey
secretKeyRef:
name: AzureCosmosDBMasterKey
key: AzureCosmosDBMasterKey

auth:
secretStore: envvar-secret-store
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: envvar-secret-store
namespace: default
spec:
type: secretstores.local.env
version: v1
metadata:
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: azure-cosmosdb-binding
namespace: default
spec:
type: bindings.azure.cosmosdb
version: v1
metadata:
- name: url
secretKeyRef:
name: AzureCosmosDBUrl
key: AzureCosmosDBUrl
- name: database
secretKeyRef:
name: AzureCosmosDB
key: AzureCosmosDB
- name: collection
secretKeyRef:
name: AzureCosmosDBCollection
key: AzureCosmosDBCollection
- name: partitionKey
value: partitionKey
- name: azureTenantId
secretKeyRef:
name: AzureCertificationTenantId
key: AzureCertificationTenantId
- name: azureClientId
secretKeyRef:
name: AzureCertificationServicePrincipalClientId
key: AzureCertificationServicePrincipalClientId
- name: azureClientSecret
secretKeyRef:
name: AzureCertificationServicePrincipalClientSecret
key: AzureCertificationServicePrincipalClientSecret

auth:
secretStore: envvar-secret-store
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: envvar-secret-store
namespace: default
spec:
type: secretstores.local.env
version: v1
metadata:
6 changes: 6 additions & 0 deletions tests/certification/bindings/azure/cosmosdb/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: keyvaultconfig
spec:
features:
82 changes: 82 additions & 0 deletions tests/certification/bindings/azure/cosmosdb/cosmosdb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation and Dapr Contributors.
// Licensed under the MIT License.
// ------------------------------------------------------------

package keyvault_test

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/dapr/components-contrib/bindings"
cosmosdbbinding "github.com/dapr/components-contrib/bindings/azure/cosmosdb"
"github.com/dapr/components-contrib/secretstores"
secretstore_env "github.com/dapr/components-contrib/secretstores/local/env"
bindings_loader "github.com/dapr/dapr/pkg/components/bindings"
secretstores_loader "github.com/dapr/dapr/pkg/components/secretstores"
"github.com/dapr/dapr/pkg/runtime"
dapr_testing "github.com/dapr/dapr/pkg/testing"
"github.com/dapr/kit/logger"

"github.com/dapr/components-contrib/tests/certification/embedded"
"github.com/dapr/components-contrib/tests/certification/flow"
"github.com/dapr/components-contrib/tests/certification/flow/sidecar"
)

const (
sidecarName = "cosmosdb-sidecar"
)

func TestKeyVault(t *testing.T) {
ports, err := dapr_testing.GetFreePorts(2)
assert.NoError(t, err)

currentGrpcPort := ports[0]
currentHttpPort := ports[1]

log := logger.NewLogger("dapr.components")

flow.New(t, "cosmosdb binding authentication using service principal").
Step(sidecar.Run(sidecarName,
embedded.WithoutApp(),
embedded.WithComponentsPath("./components/serviceprincipal"),
embedded.WithDaprGRPCPort(currentGrpcPort),
embedded.WithDaprHTTPPort(currentHttpPort),
runtime.WithSecretStores(
secretstores_loader.New("local.env", func() secretstores.SecretStore {
return secretstore_env.NewEnvSecretStore(log)
}),
),
runtime.WithOutputBindings(
bindings_loader.NewOutput("azure.cosmosdb", func() bindings.OutputBinding {
return cosmosdbbinding.NewCosmosDB(log)
}),
))).
Run()

ports, err = dapr_testing.GetFreePorts(2)
assert.NoError(t, err)

currentGrpcPort = ports[0]
currentHttpPort = ports[1]

flow.New(t, "cosmosdb binding authentication using master key").
Step(sidecar.Run(sidecarName,
embedded.WithoutApp(),
embedded.WithComponentsPath("./components/masterkey"),
embedded.WithDaprGRPCPort(currentGrpcPort),
embedded.WithDaprHTTPPort(currentHttpPort),
runtime.WithSecretStores(
secretstores_loader.New("local.env", func() secretstores.SecretStore {
return secretstore_env.NewEnvSecretStore(log)
}),
),
runtime.WithOutputBindings(
bindings_loader.NewOutput("azure.cosmosdb", func() bindings.OutputBinding {
return cosmosdbbinding.NewCosmosDB(log)
}),
))).
Run()
}
Loading

0 comments on commit 9dbdaee

Please sign in to comment.