Skip to content

Commit b582eb9

Browse files
committed
fix crossplane-contrib#106 add ability to set auth_plugin for mysql users
1 parent 4988633 commit b582eb9

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
lines changed

apis/mysql/v1alpha1/user_types.go

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ type UserParameters struct {
4949
// BinLog defines whether the create, delete, update operations of this user are propagated to replicas. Defaults to true
5050
// +optional
5151
BinLog *bool `json:"binlog,omitempty" default:"true"`
52+
53+
// AuthPlugin defines the MySQL auth plugin (ie. AWSAuthenticationPlugin for AWS IAM authentication when using AWS RDS )
54+
// See https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html
55+
// +optional
56+
AuthPlugin string `json:"authPlugin,omitempty" default:"mysql_native_password"`
5257
}
5358

5459
// ResourceOptions define the account specific resource limits.

examples/mysql/user.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ metadata:
44
name: example-user
55
spec:
66
forProvider:
7+
authPlugin: AWSAuthenticationPlugin
78
passwordSecretRef:
89
name: example-pw
910
namespace: default

package/crds/mysql.sql.crossplane.io_users.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ spec:
7171
description: UserParameters define the desired state of a MySQL user
7272
instance.
7373
properties:
74+
authPlugin:
75+
description: AuthPlugin defines the authentication plugin to be used.
76+
Meant to add support for AWS IAM DB authentication (ie. AWSAuthenticationPlugin)
77+
type: string
7478
binlog:
7579
description: BinLog defines whether the create, delete, update
7680
operations of this user are propagated to replicas. Defaults

pkg/controller/mysql/user/reconciler.go

+33-11
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const (
5454
errUpdateUser = "cannot update user"
5555
errGetPasswordSecretFailed = "cannot get password secret"
5656
errCompareResourceOptions = "cannot compare desired and observed resource options"
57+
errAuthPluginNotSupported = "auth plugin not supported"
5758

5859
maxConcurrency = 5
5960
)
@@ -238,21 +239,41 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
238239
cr.SetConditions(xpv1.Creating())
239240

240241
username, host := mysql.SplitUserHost(meta.GetExternalName(cr))
241-
pw, _, err := c.getPassword(ctx, cr)
242-
if err != nil {
243-
return managed.ExternalCreation{}, err
242+
243+
var auth string
244+
245+
ro := resourceOptionsToClauses(cr.Spec.ForProvider.ResourceOptions)
246+
binlog := cr.Spec.ForProvider.BinLog
247+
248+
var authplugin string
249+
if cr.Spec.ForProvider.AuthPlugin != "" {
250+
authplugin = cr.Spec.ForProvider.AuthPlugin
251+
} else {
252+
authplugin = "mysql_native_password"
244253
}
254+
var pw string
245255

246-
if pw == "" {
247-
pw, err = password.Generate()
256+
if authplugin == "mysql_native_password" {
257+
var err error
258+
pw, _, err = c.getPassword(ctx, cr)
248259
if err != nil {
249260
return managed.ExternalCreation{}, err
250261
}
262+
263+
if pw == "" {
264+
pw, err = password.Generate()
265+
if err != nil {
266+
return managed.ExternalCreation{}, err
267+
}
268+
}
269+
auth = fmt.Sprintf("%s BY %s", authplugin, mysql.QuoteValue(pw))
270+
} else if authplugin == "AWSAuthenticationPlugin" {
271+
auth = fmt.Sprintf("%s AS %s", authplugin, mysql.QuoteValue("RDS"))
272+
} else {
273+
return managed.ExternalCreation{}, errors.New(errAuthPluginNotSupported)
251274
}
252275

253-
ro := resourceOptionsToClauses(cr.Spec.ForProvider.ResourceOptions)
254-
binlog := cr.Spec.ForProvider.BinLog
255-
if err := c.executeCreateUserQuery(ctx, username, host, ro, pw, binlog); err != nil {
276+
if err := c.executeCreateUserQuery(ctx, username, host, ro, auth, binlog); err != nil {
256277
return managed.ExternalCreation{}, err
257278
}
258279

@@ -265,19 +286,20 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
265286
}, nil
266287
}
267288

268-
func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, pw string, binlog *bool) error {
289+
func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, auth string, binlog *bool) error {
269290
resourceOptions := ""
270291
if len(resourceOptionsClauses) != 0 {
271292
resourceOptions = fmt.Sprintf(" WITH %s", strings.Join(resourceOptionsClauses, " "))
272293
}
273294

274295
query := fmt.Sprintf(
275-
"CREATE USER %s@%s IDENTIFIED BY %s%s",
296+
"CREATE USER %s@%s IDENTIFIED WITH %s%s",
276297
mysql.QuoteValue(username),
277298
mysql.QuoteValue(host),
278-
mysql.QuoteValue(pw),
299+
auth,
279300
resourceOptions,
280301
)
302+
fmt.Println(query)
281303

282304
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil {
283305
return err

pkg/controller/mysql/user/reconciler_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,39 @@ func TestCreate(t *testing.T) {
501501
},
502502
},
503503
},
504+
"UserWithAuthPluign": {
505+
reason: "The username must be split if it contains a host",
506+
fields: fields{
507+
db: &mockDB{
508+
MockExec: func(ctx context.Context, q xsql.Query) error { return nil },
509+
},
510+
},
511+
args: args{
512+
mg: &v1alpha1.User{
513+
ObjectMeta: v1.ObjectMeta{
514+
Annotations: map[string]string{
515+
meta.AnnotationKeyExternalName: "example",
516+
},
517+
},
518+
Spec: v1alpha1.UserSpec{
519+
ForProvider: v1alpha1.UserParameters{
520+
AuthPlugin: "AWSAuthenticationPlugin",
521+
},
522+
},
523+
},
524+
},
525+
want: want{
526+
err: nil,
527+
c: managed.ExternalCreation{
528+
ConnectionDetails: managed.ConnectionDetails{
529+
xpv1.ResourceCredentialsSecretUserKey: []byte("example"),
530+
xpv1.ResourceCredentialsSecretPasswordKey: []byte(""),
531+
xpv1.ResourceCredentialsSecretEndpointKey: []byte("localhost"),
532+
xpv1.ResourceCredentialsSecretPortKey: []byte("3306"),
533+
},
534+
},
535+
},
536+
},
504537
}
505538

506539
for name, tc := range cases {

0 commit comments

Comments
 (0)