Add Azure AD support to Postgres state store component (#2970)
Signed-off-by: ItalyPaleAle <43508+ItalyPaleAle@users.noreply.github.com>
This commit is contained in:
parent
c62e7c9ad7
commit
58228efd01
|
@ -0,0 +1,68 @@
|
|||
// ------------------------------------------------------------------------
|
||||
// Copyright 2021 The Dapr Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
param postgresServerName string
|
||||
param sdkAuthSpId string
|
||||
param sdkAuthSpName string
|
||||
param rgLocation string = resourceGroup().location
|
||||
param confTestTags object = {}
|
||||
param postgresqlVersion string = '14'
|
||||
param tenantId string = subscription().tenantId
|
||||
|
||||
resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2023-03-01-preview' = {
|
||||
name: postgresServerName
|
||||
location: rgLocation
|
||||
tags: confTestTags
|
||||
sku: {
|
||||
name: 'Standard_B1ms'
|
||||
tier: 'Burstable'
|
||||
}
|
||||
properties: {
|
||||
storage: {
|
||||
storageSizeGB: 32
|
||||
autoGrow: 'Disabled'
|
||||
}
|
||||
authConfig: {
|
||||
activeDirectoryAuth: 'Enabled'
|
||||
passwordAuth: 'Disabled'
|
||||
tenantId: tenantId
|
||||
}
|
||||
network: {}
|
||||
version: postgresqlVersion
|
||||
}
|
||||
|
||||
resource daprTestDB 'databases@2023-03-01-preview' = {
|
||||
name: 'dapr_test'
|
||||
properties: {
|
||||
charset: 'UTF8'
|
||||
collation: 'en_US.utf8'
|
||||
}
|
||||
}
|
||||
|
||||
resource fwRules 'firewallRules@2023-03-01-preview' = {
|
||||
name: 'allowall'
|
||||
properties: {
|
||||
startIpAddress: '0.0.0.0'
|
||||
endIpAddress: '255.255.255.255'
|
||||
}
|
||||
}
|
||||
|
||||
resource azureAdAdmin 'administrators@2023-03-01-preview' = {
|
||||
name: sdkAuthSpId
|
||||
properties: {
|
||||
principalType: 'ServicePrincipal'
|
||||
principalName: sdkAuthSpName
|
||||
tenantId: tenantId
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
param sqlServerName string
|
||||
param rgLocation string = resourceGroup().location
|
||||
param confTestTags object = {}
|
||||
@secure()
|
||||
param sqlServerAdminPassword string
|
||||
|
||||
var sqlServerAdminName = '${sqlServerName}-admin'
|
||||
|
|
|
@ -15,7 +15,7 @@ param storageName string
|
|||
param rgLocation string = resourceGroup().location
|
||||
param confTestTags object = {}
|
||||
|
||||
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-02-01' = {
|
||||
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
|
||||
name: storageName
|
||||
sku: {
|
||||
name: 'Standard_RAGRS'
|
||||
|
@ -23,27 +23,23 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-02-01' = {
|
|||
kind: 'StorageV2'
|
||||
location: rgLocation
|
||||
tags: confTestTags
|
||||
}
|
||||
|
||||
resource blobServices 'Microsoft.Storage/storageAccounts/blobServices@2021-02-01' = {
|
||||
parent: storageAccount
|
||||
name: 'default'
|
||||
properties: {
|
||||
deleteRetentionPolicy: {
|
||||
enabled: true
|
||||
days: 1
|
||||
resource blobServices 'blobServices@2022-09-01' = {
|
||||
name: 'default'
|
||||
properties: {
|
||||
deleteRetentionPolicy: {
|
||||
enabled: true
|
||||
days: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource tableServices 'tableServices@2022-09-01' = {
|
||||
name: 'default'
|
||||
properties: {}
|
||||
|
||||
resource certificationTable 'tables@2022-09-01' = {
|
||||
name: 'certificationTable'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource tableServices 'Microsoft.Storage/storageAccounts/tableServices@2021-09-01' = {
|
||||
parent: storageAccount
|
||||
name: 'default'
|
||||
properties: {}
|
||||
}
|
||||
|
||||
resource certificationTable 'Microsoft.Storage/storageAccounts/tableServices/tables@2021-09-01' = {
|
||||
name: 'certificationTable'
|
||||
parent: tableServices
|
||||
properties: {}
|
||||
}
|
||||
|
|
|
@ -33,9 +33,12 @@ param adminId string
|
|||
|
||||
@minLength(36)
|
||||
@maxLength(36)
|
||||
@description('Provide the objectId of the Service Principal using secret auth with get access to secrets in Azure Key Vault.')
|
||||
@description('Provide the objectId of the Service Principal using secret auth with get access to secrets in Azure Key Vault and access Azure PostgreSQL')
|
||||
param sdkAuthSpId string
|
||||
|
||||
@description('Provide the name of the Service Principal using secret auth with get access to secrets in Azure Key Vault and access Azure PostgreSQL')
|
||||
param sdkAuthSpName string
|
||||
|
||||
@minLength(36)
|
||||
@maxLength(36)
|
||||
@description('Provide the objectId of the Service Principal using cert auth with get and list access to all assets in Azure Key Vault.')
|
||||
|
@ -43,6 +46,7 @@ param certAuthSpId string
|
|||
|
||||
@minLength(16)
|
||||
@description('Provide the SQL server admin password of at least 16 characters.')
|
||||
@secure()
|
||||
param sqlServerAdminPassword string
|
||||
|
||||
var confTestRgName = '${toLower(namePrefix)}-conf-test-rg'
|
||||
|
@ -54,6 +58,7 @@ var iotHubName = '${toLower(namePrefix)}-conf-test-iothub'
|
|||
var keyVaultName = '${toLower(namePrefix)}-conf-test-kv'
|
||||
var serviceBusName = '${toLower(namePrefix)}-conf-test-servicebus'
|
||||
var sqlServerName = '${toLower(namePrefix)}-conf-test-sql'
|
||||
var postgresServerName = '${toLower(namePrefix)}-conf-test-pg'
|
||||
var storageName = '${toLower(namePrefix)}ctstorage'
|
||||
|
||||
resource confTestRg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
|
||||
|
@ -72,6 +77,7 @@ module cosmosDb 'conf-test-azure-cosmosdb.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
cosmosDbName: cosmosDbName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +87,7 @@ module cosmosDbTable 'conf-test-azure-cosmosdb-table.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
cosmosDbTableAPIName: cosmosDbTableAPIName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,6 +97,7 @@ module eventGridTopic 'conf-test-azure-eventgrid.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
eventGridTopicName: eventGridTopicName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,6 +107,7 @@ module eventHubsNamespace 'conf-test-azure-eventhubs.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
eventHubsNamespaceName: eventHubsNamespaceName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +117,7 @@ module iotHub 'conf-test-azure-iothub.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
iotHubName: iotHubName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,6 +130,7 @@ module keyVault 'conf-test-azure-keyvault.bicep' = {
|
|||
certAuthSpId: certAuthSpId
|
||||
keyVaultName: keyVaultName
|
||||
sdkAuthSpId: sdkAuthSpId
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -129,6 +140,7 @@ module serviceBus 'conf-test-azure-servicebus.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
serviceBusName: serviceBusName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,6 +151,7 @@ module sqlServer 'conf-test-azure-sqlserver.bicep' = {
|
|||
confTestTags: confTestTags
|
||||
sqlServerName: sqlServerName
|
||||
sqlServerAdminPassword: sqlServerAdminPassword
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,6 +161,19 @@ module storage 'conf-test-azure-storage.bicep' = {
|
|||
params: {
|
||||
confTestTags: confTestTags
|
||||
storageName: storageName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
module postgres 'conf-test-azure-postgres.bicep' = {
|
||||
name: postgresServerName
|
||||
scope: resourceGroup(confTestRg.name)
|
||||
params: {
|
||||
confTestTags: confTestTags
|
||||
postgresServerName: postgresServerName
|
||||
sdkAuthSpId: sdkAuthSpId
|
||||
sdkAuthSpName: sdkAuthSpName
|
||||
rgLocation: rgLocation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,4 +202,5 @@ output keyVaultName string = keyVault.name
|
|||
output serviceBusName string = serviceBus.name
|
||||
output sqlServerName string = sqlServer.name
|
||||
output sqlServerAdminName string = sqlServer.outputs.sqlServerAdminName
|
||||
output postgresServerName string = postgres.name
|
||||
output storageName string = storage.name
|
||||
|
|
|
@ -229,6 +229,8 @@ SQL_SERVER_NAME_VAR_NAME="AzureSqlServerName"
|
|||
SQL_SERVER_DB_NAME_VAR_NAME="AzureSqlServerDbName"
|
||||
SQL_SERVER_CONNECTION_STRING_VAR_NAME="AzureSqlServerConnectionString"
|
||||
|
||||
AZURE_DB_POSTGRES_CONNSTRING_VAR_NAME="AzureDBPostgresConnectionString"
|
||||
|
||||
STORAGE_ACCESS_KEY_VAR_NAME="AzureBlobStorageAccessKey"
|
||||
STORAGE_ACCOUNT_VAR_NAME="AzureBlobStorageAccount"
|
||||
STORAGE_CONTAINER_VAR_NAME="AzureBlobStorageContainer"
|
||||
|
@ -269,7 +271,7 @@ if [[ -n ${CREDENTIALS_PATH} ]]; then
|
|||
fi
|
||||
SDK_AUTH_SP_NAME="$(az ad sp show --id "${SDK_AUTH_SP_APPID}" --query "appDisplayName" --output tsv)"
|
||||
SDK_AUTH_SP_ID="$(az ad sp show --id "${SDK_AUTH_SP_APPID}" --query "id" --output tsv)"
|
||||
echo "Using Service Principal from ${CREDENTIALS_PATH} for SDK Auth: ${SDK_AUTH_SP_NAME}"
|
||||
echo "Using Service Principal from ${CREDENTIALS_PATH} for SDK Auth: ${SDK_AUTH_SP_NAME} (ID: ${SDK_AUTH_SP_ID})"
|
||||
else
|
||||
SDK_AUTH_SP_NAME="${PREFIX}-conf-test-runner-sp"
|
||||
SDK_AUTH_SP_INFO="$(az ad sp create-for-rbac --name "${SDK_AUTH_SP_NAME}" --sdk-auth --years 1)"
|
||||
|
@ -277,7 +279,7 @@ else
|
|||
SDK_AUTH_SP_CLIENT_SECRET="$(echo "${SDK_AUTH_SP_INFO}" | jq -r '.clientSecret')"
|
||||
SDK_AUTH_SP_ID="$(az ad sp list --display-name "${SDK_AUTH_SP_NAME}" --query "[].id" --output tsv)"
|
||||
echo "${SDK_AUTH_SP_INFO}"
|
||||
echo "Created Service Principal for SDK Auth: ${SDK_AUTH_SP_NAME}"
|
||||
echo "Created Service Principal for SDK Auth: ${SDK_AUTH_SP_NAME} (ID: ${SDK_AUTH_SP_ID})"
|
||||
AZURE_CREDENTIALS_FILENAME="${OUTPUT_PATH}/AZURE_CREDENTIALS"
|
||||
echo "${SDK_AUTH_SP_INFO}" > "${AZURE_CREDENTIALS_FILENAME}"
|
||||
fi
|
||||
|
@ -292,7 +294,17 @@ echo "Building conf-test-azure.bicep to ${ARM_TEMPLATE_FILE} ..."
|
|||
az bicep build --file conf-test-azure.bicep --outfile "${ARM_TEMPLATE_FILE}"
|
||||
|
||||
echo "Creating azure deployment ${DEPLOY_NAME} in ${DEPLOY_LOCATION} and resource prefix ${PREFIX}-* ..."
|
||||
az deployment sub create --name "${DEPLOY_NAME}" --location "${DEPLOY_LOCATION}" --template-file "${ARM_TEMPLATE_FILE}" -p namePrefix="${PREFIX}" -p adminId="${ADMIN_ID}" -p certAuthSpId="${CERT_AUTH_SP_ID}" -p sdkAuthSpId="${SDK_AUTH_SP_ID}" -p rgLocation="${DEPLOY_LOCATION}" -p sqlServerAdminPassword="${SQL_SERVER_ADMIN_PASSWORD}"
|
||||
az deployment sub create \
|
||||
--name "${DEPLOY_NAME}" \
|
||||
--location "${DEPLOY_LOCATION}" \
|
||||
--template-file "${ARM_TEMPLATE_FILE}" \
|
||||
-p namePrefix="${PREFIX}" \
|
||||
-p adminId="${ADMIN_ID}" \
|
||||
-p certAuthSpId="${CERT_AUTH_SP_ID}" \
|
||||
-p sdkAuthSpId="${SDK_AUTH_SP_ID}" \
|
||||
-p sdkAuthSpName="${SDK_AUTH_SP_NAME}" \
|
||||
-p rgLocation="${DEPLOY_LOCATION}" \
|
||||
-p sqlServerAdminPassword="${SQL_SERVER_ADMIN_PASSWORD}"
|
||||
|
||||
echo "Sleeping for 5s to allow created ARM deployment info to propagate to query endpoints ..."
|
||||
sleep 5
|
||||
|
@ -546,6 +558,7 @@ az keyvault secret set --name "${KEYVAULT_SERVICE_PRINCIPAL_CLIENT_ID_VAR_NAME}"
|
|||
KEYVAULT_SERVICE_PRINCIPAL_CLIENT_SECRET=${AKV_SPAUTH_SP_CLIENT_SECRET}
|
||||
echo export ${KEYVAULT_SERVICE_PRINCIPAL_CLIENT_SECRET_VAR_NAME}=\"${KEYVAULT_SERVICE_PRINCIPAL_CLIENT_SECRET}\" >> "${ENV_CONFIG_FILENAME}"
|
||||
az keyvault secret set --name "${KEYVAULT_SERVICE_PRINCIPAL_CLIENT_SECRET_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${KEYVAULT_SERVICE_PRINCIPAL_CLIENT_SECRET}"
|
||||
|
||||
# ------------------------------------
|
||||
# Populate Blob Storage test settings
|
||||
# ------------------------------------
|
||||
|
@ -671,6 +684,15 @@ SQL_SERVER_CONNECTION_STRING="Server=${SQL_SERVER_NAME}.database.windows.net;por
|
|||
echo export ${SQL_SERVER_CONNECTION_STRING_VAR_NAME}=\"${SQL_SERVER_CONNECTION_STRING}\" >> "${ENV_CONFIG_FILENAME}"
|
||||
az keyvault secret set --name "${SQL_SERVER_CONNECTION_STRING_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${SQL_SERVER_CONNECTION_STRING}"
|
||||
|
||||
# ----------------------------------
|
||||
# Populate Azure Database for PostgreSQL test settings
|
||||
# ----------------------------------
|
||||
echo "Configuring Azure Database for PostgreSQL test settings ..."
|
||||
|
||||
AZURE_DB_POSTGRES_CONNSTRING="host=${PREFIX}-conf-test-pg.postgres.database.azure.com user=${SDK_AUTH_SP_NAME} port=5432 connect_timeout=30 database=dapr_test"
|
||||
echo export ${AZURE_DB_POSTGRES_CONNSTRING_VAR_NAME}=\"${AZURE_DB_POSTGRES_CONNSTRING}\" >> "${ENV_CONFIG_FILENAME}"
|
||||
az keyvault secret set --name "${AZURE_DB_POSTGRES_CONNSTRING_VAR_NAME}" --vault-name "${KEYVAULT_NAME}" --value "${AZURE_DB_POSTGRES_CONNSTRING}"
|
||||
|
||||
# ----------------------------------
|
||||
# Populate Event Hubs test settings
|
||||
# ----------------------------------
|
||||
|
|
|
@ -582,8 +582,15 @@ const components = {
|
|||
conformanceSetup: 'docker-compose.sh oracledatabase',
|
||||
},
|
||||
'state.postgresql': {
|
||||
conformance: true,
|
||||
certification: true,
|
||||
sourcePkg: [
|
||||
'state/postgresql',
|
||||
'internal/component/postgresql',
|
||||
'internal/component/sql',
|
||||
],
|
||||
},
|
||||
'state.postgresql.docker': {
|
||||
conformance: true,
|
||||
conformanceSetup: 'docker-compose.sh postgresql',
|
||||
sourcePkg: [
|
||||
'state/postgresql',
|
||||
|
@ -591,6 +598,15 @@ const components = {
|
|||
'internal/component/sql',
|
||||
],
|
||||
},
|
||||
'state.postgresql.azure': {
|
||||
conformance: true,
|
||||
requiredSecrets: ['AzureDBPostgresConnectionString'],
|
||||
sourcePkg: [
|
||||
'state/postgresql',
|
||||
'internal/component/postgresql',
|
||||
'internal/component/sql',
|
||||
],
|
||||
},
|
||||
'state.redis': {
|
||||
certification: true,
|
||||
sourcePkg: ['state/redis', 'internal/component/redis'],
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
const (
|
||||
// Service configuration for Azure SQL. Namespaced with dapr.io
|
||||
ServiceAzureSQL cloud.ServiceName = "dapr.io/azuresql"
|
||||
// Service configuration for OSS RDBMS (Azure Database for PostgreSQL and MySQL). Namespaced with dapr.io
|
||||
ServiceOSSRDBMS cloud.ServiceName = "dapr.io/oss-rdbms"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -33,4 +35,13 @@ func init() {
|
|||
cloud.AzurePublic.Services[ServiceAzureSQL] = cloud.ServiceConfiguration{
|
||||
Audience: "https://database.windows.net",
|
||||
}
|
||||
cloud.AzureChina.Services[ServiceOSSRDBMS] = cloud.ServiceConfiguration{
|
||||
Audience: "https://ossrdbms-aad.database.chinacloudapi.cn",
|
||||
}
|
||||
cloud.AzureGovernment.Services[ServiceOSSRDBMS] = cloud.ServiceConfiguration{
|
||||
Audience: "https://ossrdbms-aad.database.usgovcloudapi.net",
|
||||
}
|
||||
cloud.AzurePublic.Services[ServiceOSSRDBMS] = cloud.ServiceConfiguration{
|
||||
Audience: "https://ossrdbms-aad.database.windows.net",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,15 @@ limitations under the License.
|
|||
package postgresql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"github.com/dapr/components-contrib/internal/authentication/azure"
|
||||
"github.com/dapr/components-contrib/metadata"
|
||||
"github.com/dapr/components-contrib/state"
|
||||
"github.com/dapr/kit/ptr"
|
||||
|
@ -33,13 +39,19 @@ const (
|
|||
)
|
||||
|
||||
type postgresMetadataStruct struct {
|
||||
ConnectionString string
|
||||
ConnectionMaxIdleTime time.Duration
|
||||
TableName string // Could be in the format "schema.table" or just "table"
|
||||
MetadataTableName string // Could be in the format "schema.table" or just "table"
|
||||
ConnectionString string `mapstructure:"connectionString"`
|
||||
ConnectionMaxIdleTime time.Duration `mapstructure:"connectionMaxIdleTime"`
|
||||
TableName string `mapstructure:"tableName"` // Could be in the format "schema.table" or just "table"
|
||||
MetadataTableName string `mapstructure:"metadataTableName"` // Could be in the format "schema.table" or just "table"
|
||||
Timeout time.Duration `mapstructure:"timeoutInSeconds"`
|
||||
CleanupInterval *time.Duration `mapstructure:"cleanupIntervalInSeconds"`
|
||||
MaxConns int `mapstructure:"maxConns"`
|
||||
UseAzureAD bool `mapstructure:"useAzureAD"`
|
||||
|
||||
Timeout time.Duration `mapstructure:"timeoutInSeconds"`
|
||||
CleanupInterval *time.Duration `mapstructure:"cleanupIntervalInSeconds"`
|
||||
// Set to true if the component can support authentication with Azure AD.
|
||||
// This is different from the "useAzureAD" property above, which is provided by the user and instructs the component to authenticate using Azure AD.
|
||||
azureADEnabled bool
|
||||
azureEnv azure.EnvironmentSettings
|
||||
}
|
||||
|
||||
func (m *postgresMetadataStruct) InitWithMetadata(meta state.Metadata) error {
|
||||
|
@ -79,5 +91,67 @@ func (m *postgresMetadataStruct) InitWithMetadata(meta state.Metadata) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Populate the Azure environment if using Azure AD
|
||||
if m.azureADEnabled && m.UseAzureAD {
|
||||
m.azureEnv, err = azure.NewEnvironmentSettings(meta.Properties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPgxPoolConfig returns the pgxpool.Config object that contains the credentials for connecting to Postgres.
|
||||
func (m *postgresMetadataStruct) GetPgxPoolConfig() (*pgxpool.Config, error) {
|
||||
// Get the config from the connection string
|
||||
config, err := pgxpool.ParseConfig(m.ConnectionString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse connection string: %w", err)
|
||||
}
|
||||
if m.ConnectionMaxIdleTime > 0 {
|
||||
config.MaxConnIdleTime = m.ConnectionMaxIdleTime
|
||||
}
|
||||
if m.MaxConns > 1 {
|
||||
config.MaxConns = int32(m.MaxConns)
|
||||
}
|
||||
|
||||
// Check if we should use Azure AD
|
||||
if m.azureADEnabled && m.UseAzureAD {
|
||||
tokenCred, errToken := m.azureEnv.GetTokenCredential()
|
||||
if errToken != nil {
|
||||
return nil, errToken
|
||||
}
|
||||
|
||||
// Reset the password
|
||||
config.ConnConfig.Password = ""
|
||||
|
||||
/*// For Azure AD, using SSL is required
|
||||
// If not already enabled, configure TLS without certificate validation
|
||||
if config.ConnConfig.TLSConfig == nil {
|
||||
config.ConnConfig.TLSConfig = &tls.Config{
|
||||
//nolint:gosec
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}*/
|
||||
|
||||
// We need to retrieve the token every time we attempt a new connection
|
||||
// This is because tokens expire, and connections can drop and need to be re-established at any time
|
||||
// Fortunately, we can do this with the "BeforeConnect" hook
|
||||
config.BeforeConnect = func(ctx context.Context, cc *pgx.ConnConfig) error {
|
||||
at, err := tokenCred.GetToken(ctx, policy.TokenRequestOptions{
|
||||
Scopes: []string{
|
||||
m.azureEnv.Cloud.Services[azure.ServiceOSSRDBMS].Audience + "/.default",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cc.Password = at.Token
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
|
|
@ -67,7 +67,10 @@ func newPostgresDBAccess(logger logger.Logger, opts Options) *PostgresDBAccess {
|
|||
logger.Debug("Instantiating new Postgres state store")
|
||||
|
||||
return &PostgresDBAccess{
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
metadata: postgresMetadataStruct{
|
||||
azureADEnabled: opts.EnableAzureAD,
|
||||
},
|
||||
migrateFn: opts.MigrateFn,
|
||||
setQueryFn: opts.SetQueryFn,
|
||||
etagColumn: opts.ETagColumn,
|
||||
|
@ -84,15 +87,11 @@ func (p *PostgresDBAccess) Init(ctx context.Context, meta state.Metadata) error
|
|||
return err
|
||||
}
|
||||
|
||||
config, err := pgxpool.ParseConfig(p.metadata.ConnectionString)
|
||||
config, err := p.metadata.GetPgxPoolConfig()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to parse connection string: %w", err)
|
||||
p.logger.Error(err)
|
||||
return err
|
||||
}
|
||||
if p.metadata.ConnectionMaxIdleTime > 0 {
|
||||
config.MaxConnIdleTime = p.metadata.ConnectionMaxIdleTime
|
||||
}
|
||||
|
||||
connCtx, connCancel := context.WithTimeout(ctx, p.metadata.Timeout)
|
||||
p.db, err = pgxpool.NewWithConfig(connCtx, config)
|
||||
|
|
|
@ -31,9 +31,10 @@ type PostgreSQL struct {
|
|||
}
|
||||
|
||||
type Options struct {
|
||||
MigrateFn func(context.Context, PGXPoolConn, MigrateOptions) error
|
||||
SetQueryFn func(*state.SetRequest, SetQueryOptions) string
|
||||
ETagColumn string
|
||||
MigrateFn func(context.Context, PGXPoolConn, MigrateOptions) error
|
||||
SetQueryFn func(*state.SetRequest, SetQueryOptions) string
|
||||
ETagColumn string
|
||||
EnableAzureAD bool
|
||||
}
|
||||
|
||||
type MigrateOptions struct {
|
||||
|
|
|
@ -16,14 +16,35 @@ capabilities:
|
|||
- etag
|
||||
- query
|
||||
- ttl
|
||||
builtinAuthenticationProfiles:
|
||||
- name: "azuread"
|
||||
metadata:
|
||||
- name: useAzureAD
|
||||
required: true
|
||||
type: bool
|
||||
example: '"true"'
|
||||
description: |
|
||||
Must be set to `true` to enable the component to retrieve access tokens from Azure AD.
|
||||
This authentication method only works with Azure Database for PostgreSQL databases.
|
||||
- name: connectionString
|
||||
required: true
|
||||
sensitive: true
|
||||
description: |
|
||||
The connection string for the PostgreSQL database
|
||||
This must contain the user, which corresponds to the name of the user created inside PostgreSQL that maps to the Azure AD identity; this is often the name of the corresponding principal (e.g. the name of the Azure AD application). This connection string should not contain any password.
|
||||
example: |
|
||||
"host=mydb.postgres.database.azure.com user=myapplication port=5432 database=dapr_test sslmode=require"
|
||||
type: string
|
||||
authenticationProfiles:
|
||||
- title: "Connection string"
|
||||
description: "Authenticate using a Connection String."
|
||||
metadata:
|
||||
- name: connectionString
|
||||
required: true
|
||||
sensitive: true
|
||||
description: The connection string for the PostgreSQL database
|
||||
example: "host=localhost user=postgres password=example port=5432 connect_timeout=10 database=dapr_test"
|
||||
example: |
|
||||
"host=localhost user=postgres password=example port=5432 connect_timeout=10 database=dapr_test"
|
||||
type: string
|
||||
metadata:
|
||||
- name: timeoutInSeconds
|
||||
|
@ -56,6 +77,14 @@ metadata:
|
|||
example: "1800"
|
||||
default: "3600" # 1h
|
||||
type: number
|
||||
- name: maxConns
|
||||
required: false
|
||||
description: |
|
||||
Maximum number of connections pooled by this component.
|
||||
Set to 0 or lower to use the default value, which is the greater of 4 or the number of CPUs.
|
||||
example: "4"
|
||||
default: "0"
|
||||
type: number
|
||||
- name: connectionMaxIdleTime
|
||||
required: false
|
||||
description: |
|
||||
|
|
|
@ -22,8 +22,9 @@ import (
|
|||
// NewPostgreSQLStateStore creates a new instance of PostgreSQL state store.
|
||||
func NewPostgreSQLStateStore(logger logger.Logger) state.Store {
|
||||
return postgresql.NewPostgreSQLStateStore(logger, postgresql.Options{
|
||||
ETagColumn: "xmin",
|
||||
MigrateFn: performMigration,
|
||||
ETagColumn: "xmin",
|
||||
EnableAzureAD: true,
|
||||
MigrateFn: performMigration,
|
||||
SetQueryFn: func(req *state.SetRequest, opts postgresql.SetQueryOptions) string {
|
||||
// Sprintf is required for table name because the driver does not substitute parameters for table names.
|
||||
if !req.HasETag() {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: dapr.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: statestore
|
||||
spec:
|
||||
type: state.postgresql
|
||||
version: v1
|
||||
metadata:
|
||||
- name: connectionString
|
||||
value: "${{AzureDBPostgresConnectionString}}"
|
||||
- name: useAzureAD
|
||||
value: "true"
|
|
@ -32,7 +32,12 @@ components:
|
|||
config:
|
||||
# This component requires etags to be hex-encoded numbers
|
||||
badEtag: "FFFF"
|
||||
- component: postgresql
|
||||
- component: postgresql.docker
|
||||
operations: [ "transaction", "etag", "first-write", "query", "ttl" ]
|
||||
config:
|
||||
# This component requires etags to be numeric
|
||||
badEtag: "1"
|
||||
- component: postgresql.azure
|
||||
operations: [ "transaction", "etag", "first-write", "query", "ttl" ]
|
||||
config:
|
||||
# This component requires etags to be numeric
|
||||
|
|
|
@ -119,7 +119,6 @@ const (
|
|||
eventhubs = "azure.eventhubs"
|
||||
redisv6 = "redis.v6"
|
||||
redisv7 = "redis.v7"
|
||||
postgres = "postgres"
|
||||
kafka = "kafka"
|
||||
generateUUID = "$((uuid))"
|
||||
generateEd25519PrivateKey = "$((ed25519PrivateKey))"
|
||||
|
@ -438,7 +437,7 @@ func loadConfigurationStore(tc TestComponent) (configuration.Store, configupdate
|
|||
case redisv7:
|
||||
store = c_redis.NewRedisConfigurationStore(testLogger)
|
||||
updater = cu_redis.NewRedisConfigUpdater(testLogger)
|
||||
case postgres:
|
||||
case "postgres":
|
||||
store = c_postgres.NewPostgresConfigurationStore(testLogger)
|
||||
updater = cu_postgres.NewPostgresConfigUpdater(testLogger)
|
||||
default:
|
||||
|
@ -543,10 +542,12 @@ func loadStateStore(tc TestComponent) state.Store {
|
|||
case "mongodb":
|
||||
store = s_mongodb.NewMongoDB(testLogger)
|
||||
case "azure.sql":
|
||||
fallthrough
|
||||
store = s_sqlserver.New(testLogger)
|
||||
case "sqlserver":
|
||||
store = s_sqlserver.New(testLogger)
|
||||
case "postgresql":
|
||||
case "postgresql.docker":
|
||||
store = s_postgresql.NewPostgreSQLStateStore(testLogger)
|
||||
case "postgresql.azure":
|
||||
store = s_postgresql.NewPostgreSQLStateStore(testLogger)
|
||||
case "sqlite":
|
||||
store = s_sqlite.NewSQLiteStateStore(testLogger)
|
||||
|
|
Loading…
Reference in New Issue