diff --git a/docs/azure-sql-db-failover-group.md b/docs/azure-sql-db-failover-group.md index 5831352..314a24f 100644 --- a/docs/azure-sql-db-failover-group.md +++ b/docs/azure-sql-db-failover-group.md @@ -22,7 +22,7 @@ 1. Login to the primary database, create a new user with password. - 2. Grant permission "CONTROL" to the user. + 2. Alter roles (default to db_owner) to the user.  3. Collect [credentials](./azure-sql-db-failover-group.md#format-of-credentials). @@ -30,7 +30,7 @@ * Binding would fail after failover because of the change of the primary role. Please bind before failover or fail back to bind. If you do have a case which has to bind after failover, please open a Github issue to request our improvement. - * Permission "CONTROL" has full permissions in a database: https://msdn.microsoft.com/en-us/library/ms178569.aspx + * See details about fixed roles: https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-2017#fixed-database-roles. ### Unbind @@ -95,6 +95,20 @@ } ``` + And here is an optional provisioning parameter `userRoles` you can add to the json file, to specify the roles of the new users created in binding. If not present, the default role is db_owner. More details about roles: https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-2017#fixed-database-roles. + + For example, + + ``` + { + "primaryServerName": "sqlservera", + "primaryDbName": "sqldba", + "secondaryServerName": "sqlserverb", + "failoverGroupName": "failovergroupa", + "userRoles": ["db_datareader", "db_datawriter"] + } + ``` + **NOTE:** * Again, this module assumes you already have two existing servers and the target database on the primary server to get geo-replication, and these servers are provided in the meta service broker manifest file. See the "Modules related configurations" section [here](https://github.com/Azure/meta-azure-service-broker/blob/master/docs/how-admin-deploy-the-broker.md#deploy-the-meta-azure-service-broker-as-an-application-in-cloud-foundry) for details. For example, the above provisioning parameters should have the following servers provided in the broker manifest: diff --git a/examples/sqldb-failover-group-example-config.json b/examples/sqldb-failover-group-example-config.json index abe9d45..0c17d1d 100644 --- a/examples/sqldb-failover-group-example-config.json +++ b/examples/sqldb-failover-group-example-config.json @@ -1,9 +1,10 @@ /* { - "primaryServerName": "", // [Required] The resource group name, admin login, and admin login password of this server should be provided in broker manifest. - "primaryDbName": "", // [Required] The existing database on the primary server. - "secondaryServerName": "", // [Required] The resource group name, admin login, and admin login password of this server should be provided in broker manifest. - "failoverGroupName": "" // [Required] The name of the new failover group. + "primaryServerName": "", // [Required] The resource group name, admin login, and admin login password of this server should be provided in broker manifest. + "primaryDbName": "", // [Required] The existing database on the primary server. + "secondaryServerName": "", // [Required] The resource group name, admin login, and admin login password of this server should be provided in broker manifest. + "failoverGroupName": "", // [Required] The name of the new failover group. + "userRoles": // [Optional] If not present, default to db_owner in the broker manifest. See about fixed roles: https://docs.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-2017#fixed-database-roles. } */ @@ -12,5 +13,6 @@ "primaryServerName": "sqlservera", "primaryDbName": "sqldba", "secondaryServerName": "sqlserverb", - "failoverGroupName": "failovergroupa" + "failoverGroupName": "failovergroupa", + "userRoles": ["db_datareader", "db_datawriter"] } diff --git a/lib/common/index.js b/lib/common/index.js index 883dd7c..a1267ff 100644 --- a/lib/common/index.js +++ b/lib/common/index.js @@ -87,7 +87,8 @@ var validateConfigurations = function() { 'DEFAULT_PARAMETERS_AZURE_COSMOSDB', 'DEFAULT_PARAMETERS_AZURE_MYSQLDB', 'DEFAULT_PARAMETERS_AZURE_POSTGRESQLDB', - 'DEFAULT_PARAMETERS_AZURE_SQLDB' + 'DEFAULT_PARAMETERS_AZURE_SQLDB', + 'DEFAULT_PARAMETERS_AZURE_SQLDB_FAILOVER_GROUP' ]; envVarShouldBeJSON.forEach(function(envVarName) { if (process.env[envVarName]) { diff --git a/lib/services/azuresqldbfailovergroup/client.js b/lib/services/azuresqldbfailovergroup/client.js index 7268c12..c6d25c9 100644 --- a/lib/services/azuresqldbfailovergroup/client.js +++ b/lib/services/azuresqldbfailovergroup/client.js @@ -134,10 +134,10 @@ sqldbfgOperations.prototype.dropDatabaseUser = function (serverDomainName, admin that.executeSql(config, sql, callback); }; -sqldbfgOperations.prototype.grantControlToUser = function (serverDomainName, adminLogin, adminLoginPassword, databaseUser, callback) { +sqldbfgOperations.prototype.alterRoleToUser = function (serverDomainName, adminLogin, adminLoginPassword, databaseUser, roleName, callback) { var that = this; var config = getDbConnectionConfig(serverDomainName, adminLogin, adminLoginPassword, that.dbName); - var sql = util.format('GRANT CONTROL to "%s"', databaseUser); + var sql = util.format('ALTER ROLE %s ADD MEMBER "%s"', roleName, databaseUser); that.executeSql(config, sql, callback); }; diff --git a/lib/services/azuresqldbfailovergroup/cmd-bind.js b/lib/services/azuresqldbfailovergroup/cmd-bind.js index 771a2dd..7b6106d 100644 --- a/lib/services/azuresqldbfailovergroup/cmd-bind.js +++ b/lib/services/azuresqldbfailovergroup/cmd-bind.js @@ -19,6 +19,7 @@ var sqldbfgBind = function (params) { var secondaryResourceGroupName = provisioningResult.secondaryResourceGroupName || ''; var secondaryServerName = reqParams.secondaryServerName || ''; var failoverGroupName = reqParams.failoverGroupName || ''; + var userRoles = reqParams.userRoles || ''; log.info(util.format('cmd-bind: primaryResourceGroupName: %s, primaryServerName: %s, primaryDbName: %s', primaryResourceGroupName, primaryServerName, primaryDbName)); @@ -61,15 +62,29 @@ var sqldbfgBind = function (params) { ); }, function (callback) { - sqldbfgOperations.grantControlToUser( - provisioningResult.primaryFQDN, - primaryAdministratorLogin, - primaryAdministratorLoginPassword, - databaseUser, + var n = userRoles.length; + var i = 0; + async.whilst( + function() { + return i < n; + }, + function(cb) { + sqldbfgOperations.alterRoleToUser( + provisioningResult.primaryFQDN, + primaryAdministratorLogin, + primaryAdministratorLoginPassword, + databaseUser, + userRoles[i], + function(err) { + if (err) { + log.error('cmd-bind: async.waterfall/alterRoleToUser: err: %j', err); + } + i++; + cb(err); + } + ); + }, function(err) { - if (err) { - log.error('cmd-bind: async.waterfall/grantControlToUser: err: %j', err); - } callback(err); } ); diff --git a/lib/services/azuresqldbfailovergroup/cmd-provision.js b/lib/services/azuresqldbfailovergroup/cmd-provision.js index 9da1b6b..0a84b65 100644 --- a/lib/services/azuresqldbfailovergroup/cmd-provision.js +++ b/lib/services/azuresqldbfailovergroup/cmd-provision.js @@ -18,6 +18,7 @@ var sqldbfgProvision = function (params) { var primaryDbName = reqParams.primaryDbName || ''; var secondaryServerName = reqParams.secondaryServerName || ''; var failoverGroupName = reqParams.failoverGroupName || ''; + var userRoles = reqParams.userRoles || ''; this.provision = function (sqldbfgOperations, next) { var primaryFQDN, secondaryFQDN; @@ -172,6 +173,9 @@ var sqldbfgProvision = function (params) { } } + if (!_.isArray(userRoles)) { + ret.push('userRoles'); + } return ret; }; diff --git a/lib/services/azuresqldbfailovergroup/index.js b/lib/services/azuresqldbfailovergroup/index.js index f1fe567..d2e732f 100644 --- a/lib/services/azuresqldbfailovergroup/index.js +++ b/lib/services/azuresqldbfailovergroup/index.js @@ -18,7 +18,8 @@ var uuid = require('uuid'); var Handlers = {}; -Handlers.fixParameters = function(parameters, accountPool) { +Handlers.fixParameters = function(parameters) { + parameters = common.fixParametersWithDefaults('DEFAULT_PARAMETERS_AZURE_SQLDB_FAILOVER_GROUP', parameters); return parameters; }; diff --git a/manifest.yml b/manifest.yml index 6bd6fbd..a530fd3 100644 --- a/manifest.yml +++ b/manifest.yml @@ -112,3 +112,6 @@ applications: } } }' + DEFAULT_PARAMETERS_AZURE_SQLDB_FAILOVER_GROUP: '{ + "userRoles": ["db_owner"] + }' diff --git a/pcf-tile/tile-history.yml b/pcf-tile/tile-history.yml index a6596ab..1d7def6 100644 --- a/pcf-tile/tile-history.yml +++ b/pcf-tile/tile-history.yml @@ -6,5 +6,5 @@ history: - 1.2.1 - 1.3.0 - 1.4.0 -- 1.5.0 -version: 1.5.1 +- 1.5.1 +version: 1.5.2 diff --git a/pcf-tile/tile.yml b/pcf-tile/tile.yml index e04ec1a..7ef9c84 100644 --- a/pcf-tile/tile.yml +++ b/pcf-tile/tile.yml @@ -282,6 +282,14 @@ forms: } } } + label: Default Parameters of Azure SQL Database Failover Group service + - name: default_parameters_azure_sqldb_failover_group + type: text + configurable: true + default: | + { + "userRoles": ["db_owner"] + } label: Default Parameters of Azure SQL Database service # Add any dependencies your tile has on other installed products. diff --git a/test/integration/submatrix/sqldbfg.js b/test/integration/submatrix/sqldbfg.js index 6f0d5a9..57fc117 100644 --- a/test/integration/submatrix/sqldbfg.js +++ b/test/integration/submatrix/sqldbfg.js @@ -61,7 +61,8 @@ azuresqldbfg = { 'primaryServerName': primaryServerName, 'primaryDbName': primaryDbName, 'secondaryServerName': secondaryServerName, - 'failoverGroupName': failoverGroupName + 'failoverGroupName': failoverGroupName, + 'userRoles': ['db_owner'] }, bindingParameters: {}, credentials: { diff --git a/test/unit/services/azuresqldbfailovergroup/provision-spec.js b/test/unit/services/azuresqldbfailovergroup/provision-spec.js index c070b94..de27dda 100644 --- a/test/unit/services/azuresqldbfailovergroup/provision-spec.js +++ b/test/unit/services/azuresqldbfailovergroup/provision-spec.js @@ -32,7 +32,8 @@ describe('SqlDbFailoverGroup - Provision - PreConditions', function () { 'primaryServerName': 'fakeservera', 'primaryDbName': 'sqldba', 'secondaryServerName': 'fakeserverb', - 'failoverGroupName': 'failovergroupa' + 'failoverGroupName': 'failovergroupa', + 'userRoles': ['db_owner'] }, azure: azure, accountPool: { @@ -71,7 +72,8 @@ describe('SqlDbFailoverGroup - Provision - PreConditions', function () { 'primaryServerName': 'fakeservera', 'primaryDbName': 'sqldba', 'secondaryServerName': 'fakeserverb', - 'failoverGroupName': 'failovergroupa' + 'failoverGroupName': 'failovergroupa', + 'userRoles': ['db_owner'] }, azure: azure, accountPool: {} @@ -101,12 +103,13 @@ describe('SqlDbFailoverGroup - Provision - PreConditions', function () { }); it('should fail to validate the parameters', function () { - (cp.getInvalidParams().length).should.equal(4); + (cp.getInvalidParams().length).should.equal(5); cp.getInvalidParams().should.deepEqual([ 'primaryServerName', 'primaryDbName', 'secondaryServerName', - 'failoverGroupName' + 'failoverGroupName', + 'userRoles' ]); }); });