Skip to content

Commit 199a5dd

Browse files
committed
Add Azure AD authentication support
1 parent 0ff7af9 commit 199a5dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+7293
-2
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ data/
3333
postgresql/pwfile
3434
tests/docker-compose.*.yml
3535
terraform-provider-postgresql
36+
37+
38+
examples

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module github.com/terraform-providers/terraform-provider-postgresql
33
go 1.14
44

55
require (
6+
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.13.4
7+
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.7.1
68
github.com/blang/semver v3.5.1+incompatible
79
github.com/hashicorp/terraform-plugin-sdk v1.0.0
810
github.com/lib/pq v1.9.0

go.sum

Lines changed: 33 additions & 2 deletions
Large diffs are not rendered by default.

postgresql/config.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"sync"
1111
"unicode"
1212

13+
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
14+
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
1315
"github.com/blang/semver"
1416
_ "github.com/lib/pq" //PostgreSQL db
1517
"gocloud.dev/postgres"
@@ -125,6 +127,10 @@ type Config struct {
125127
Password string
126128
DatabaseUsername string
127129
Superuser bool
130+
AadAuthEnabled bool
131+
AadSpClientId string
132+
AadSpClientSecret string
133+
AadSpTenantId string
128134
SSLMode string
129135
ApplicationName string
130136
Timeout int
@@ -135,6 +141,34 @@ type Config struct {
135141
SSLRootCertPath string
136142
}
137143

144+
// Interface to Azure identity provider
145+
type AzureIdentiferInterface interface {
146+
GetAccessToken() (string, error)
147+
}
148+
149+
type AzureIdentifier struct {
150+
tenantID string
151+
clientID string
152+
clientSecret string
153+
}
154+
155+
func (a *AzureIdentifier) GetAccessToken() (string, error) {
156+
clientSecretCredentialOptions := azidentity.DefaultClientSecretCredentialOptions()
157+
clientCredential, err := azidentity.NewClientSecretCredential(a.tenantID, a.clientID, a.clientSecret, &clientSecretCredentialOptions)
158+
if err != nil {
159+
return "", fmt.Errorf("Error getting access token from Azure AD with client id (%s) in tenant (%s) (NewClientSecretCredential) : %w", a.clientID, a.tenantID, err)
160+
}
161+
ctx := context.Background()
162+
tokenOptions := azcore.TokenRequestOptions{
163+
Scopes: []string{"https://ossrdbms-aad.database.windows.net/.default"},
164+
}
165+
token, err := clientCredential.GetToken(ctx, tokenOptions)
166+
if err != nil {
167+
return "", fmt.Errorf("Error getting access token from Azure AD with client id (%s) in tenant (%s) (GetToken) : %w", a.clientID, a.tenantID, err)
168+
}
169+
return token.Token, nil
170+
}
171+
138172
// Client struct holding connection string
139173
type Client struct {
140174
// Configuration for the client
@@ -148,13 +182,16 @@ type Client struct {
148182
// catalogs look like tables, but are not in-fact able to be
149183
// concurrently updated.
150184
catalogLock sync.RWMutex
185+
186+
azIdentifer AzureIdentiferInterface
151187
}
152188

153189
// NewClient returns client config for the specified database.
154190
func (c *Config) NewClient(database string) *Client {
155191
return &Client{
156192
config: *c,
157193
databaseName: database,
194+
azIdentifer: &AzureIdentifier{c.AadSpTenantId, c.AadSpClientId, c.AadSpClientSecret},
158195
}
159196
}
160197

@@ -236,6 +273,15 @@ func (c *Config) getDatabaseUsername() string {
236273
// Callers must return their database resources. Use of QueryRow() or Exec() is encouraged.
237274
// Query() must have their rows.Close()'ed.
238275
func (c *Client) Connect() (*DBConnection, error) {
276+
// Fetch AAD access token and use it as a password if AAD authentication is enabled
277+
if c.config.AadAuthEnabled {
278+
pass, err := c.azIdentifer.GetAccessToken()
279+
if err != nil {
280+
return nil, err
281+
}
282+
c.config.Password = pass
283+
}
284+
239285
dbRegistryLock.Lock()
240286
defer dbRegistryLock.Unlock()
241287

postgresql/provider.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ func Provider() terraform.ResourceProvider {
7575
"If not, some feature might be disabled (e.g.: Refreshing state password from Postgres)",
7676
},
7777

78+
"aad_auth_enabled": {
79+
Type: schema.TypeBool,
80+
Optional: true,
81+
DefaultFunc: schema.EnvDefaultFunc("PG_AAD_AUTH_ENABLED", false),
82+
Description: "Specify if AAD authentication is used or not",
83+
},
84+
"aad_sp_client_id": {
85+
Type: schema.TypeString,
86+
Optional: true,
87+
DefaultFunc: schema.EnvDefaultFunc("PG_AAD_SP_CLIENT_ID", nil),
88+
Description: "Client id of the service principal used when connecting with Azure AD",
89+
},
90+
"aad_sp_client_secret": {
91+
Type: schema.TypeString,
92+
Optional: true,
93+
DefaultFunc: schema.EnvDefaultFunc("PG_AAD_SP_CLIENT_SECRET", nil),
94+
Description: "Client secret of the service principal used when connecting with Azure AD",
95+
Sensitive: true,
96+
},
97+
"aad_sp_tenant_id": {
98+
Type: schema.TypeString,
99+
Optional: true,
100+
DefaultFunc: schema.EnvDefaultFunc("PG_AAD_SP_TENANT_ID", nil),
101+
Description: "Tenant of the service principal used when connecting with Azure AD",
102+
},
103+
78104
"sslmode": {
79105
Type: schema.TypeString,
80106
Optional: true,
@@ -177,6 +203,10 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
177203
Password: d.Get("password").(string),
178204
DatabaseUsername: d.Get("database_username").(string),
179205
Superuser: d.Get("superuser").(bool),
206+
AadAuthEnabled: d.Get("aad_auth_enabled").(bool),
207+
AadSpClientId: d.Get("aad_sp_client_id").(string),
208+
AadSpClientSecret: d.Get("aad_sp_client_secret").(string),
209+
AadSpTenantId: d.Get("aad_sp_tenant_id").(string),
180210
SSLMode: sslMode,
181211
ApplicationName: "Terraform provider",
182212
ConnectTimeoutSec: d.Get("connect_timeout").(int),

vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/LICENSE

Lines changed: 202 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/README.md

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)