Automating SQL User Generation and Password Rotation With CockroachDB
As with most of my tutorials, topic ideas come from user inquiries. This tutorial will demonstrate SQL user generation and passwords rotation programmatically.
Join the DZone community and get the full member experience.
Join For FreeMotivation
As with most of my tutorials, topic ideas come from user inquiries. I see this question come up quite often and we don't have a documented approach to bridge the gap today. Cockroach Labs engineering is hard at work to build an API that will make this point moot but until then this can be a viable alternative. It is primarily directed at our cloud offering where we rely on password authentication today. There are also cases where password authentication serves other purposes and we need ways to automate the provisioning of passwords other than ALTER USER username WITH PASSWORD "password";
command.
You can take this approach and incorporate it into your CI/CD pipelines to onboard new users and manage their passwords in absence of certificate-based authentication and its associated revocation mechanisms or directory services and its password management capabilities.
Check out this page for more database-related articles.
High-Level Steps
- Access a CockroachDB cluster with admin privileges
- Generate a password
- Add a user with the generated password to CockroachDB
- Verify
- Rotating passwords
- Verify
- Clean up
Step by Step Instructions
Access CockroachDB Cluster With Admin Privileges
I will be using CockroachCloud Free cluster for the purposes of this tutorial but you can use any type of deployment that suits you.
The authorized users are located in system.users
table.
artem@free-tier.gcp-us-central1.cockroachlabs.cloud:26257/defaultdb> select * from system.users;
username | hashedPassword | isRole
-----------+--------------------------------------------------------------+---------
admin | | true
artem | $2a$10$9DjXsaAVmYYvU63T4XLHpuzvF82PQ2yr1v0thLM5U8Q5/sTcuamWe | false
root | | false
(3 rows)
Let's create a user roach
with password roach
to demonstrate the salient point. We can create this user by directly inserting an entry into the table.
INSERT INTO system.users VALUES ('roach', 'roach', false);
Let's try to log in using this new user.
cockroach sql --url 'postgresql://roach:roach@clustername:26257/defaultdb?sslmode=...'
#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
ERROR: password authentication failed for user roach
Failed running "sql"
I removed the sensitive information from the connection string as it is not as important as the postgresql://roach:roach@
section.
The main point is it did not work because we attempted to insert the user using a clear-text password. The table expects the password in hashed form. The main question is how to generate this hashed password? We need to inspect the source code.
Generate a Hashed Password
I created a stand-alone program to generate passwords. I'm new to Go, I hope you can forgive the user experience of the program.
package main
import (
"crypto/sha256"
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
var BcryptCost = bcrypt.DefaultCost
var sha256NewSum = sha256.New().Sum(nil)
var test = append([]byte("roach"), sha256NewSum...)
hashedPassword, err := bcrypt.GenerateFromPassword(test, BcryptCost)
if err != nil {
return
}
fmt.Printf("%s", hashedPassword)
}
As of CockroachDB 21.1, this is all you need to generate a hashed password. Now all is left is to run the code and replace the clear text password with the hashed one.
go run .
$2a$10$uI7GAG9NnsBSV.gsla4eGu6xXvYGpyR95Zl.BrYbyzoMcg0o8Zf0u%
The details of the hashing function and bcrypt library can be found in the Golang documentation.
Add User With Generated Password to CockroachDB
The second line of the output is the hashed password. Let's insert it into the users' table. But first, we need to delete this user from the table.
DELETE FROM system.users WHERE username = 'roach';
We could've also updated the password instead of deleting the user but I will show that shortly when I touch on rotating passwords.
INSERT INTO system.users VALUES ('roach', '$2a$10$uI7GAG9NnsBSV.gsla4eGu6xXvYGpyR95Zl.BrYbyzoMcg0o8Zf0u%', false);
Verify
Now let's login into CockroachDB using this user and password:
cockroach sql --url 'postgresql://roach:roach@clustername:26257/defaultdb?sslmode=verify-full...'
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
# Client version: CockroachDB CCL v21.1.9 (x86_64-apple-darwin19, built 2021/09/20 21:50:33, go1.15.14)
# Server version: CockroachDB CCL v21.1.6 (x86_64-unknown-linux-gnu, built 2021/07/20 15:30:39, go1.15.11)
warning: server version older than client! proceed with caution; some features may not be available.
# Cluster ID: c0854300-2c35-44b4-a7d1-2af71acd3e4c
#
# Enter \? for a brief introduction.
#
roach@free-tier.gcp-us-central1.cockroachlabs.cloud:26257/defaultdb>
We are in, notice I am using roach
user to connect.
Let's view the users again:
select * from system.users;
username | hashedPassword | isRole
-----------+---------------------------------------------------------------+---------
admin | | true
artem | $2a$10$9DjXsaAVmYYvU63T4XLHpuzvF82PQ2yr1v0thLM5U8Q5/sTcuamWe | false
roach | $2a$10$uI7GAG9NnsBSV.gsla4eGu6xXvYGpyR95Zl.BrYbyzoMcg0o8Zf0u% | false
root | | false
(4 rows)
So this is great and fits our requirements. Let's now cover the second part of the scenario, where we need to rotate passwords programmatically.
Rotating passwords
It's just as trivial, we need to hash a new password and update the system.users
table with this new password.
I'm going to change roach
user's password to changeme
from roach
. I will run my go program to get a new hash. The only line I change is:
var test = append([]byte("changeme"), sha256NewSum...)
I promise when I read up more on Go, I will change it to a command-line argument instead of hard coding!
Save the code and run it again. The output for the program is: $2a$10$6Nxt.d8fxDcrJWZ6Y5QDZe8IecbBYMBCNmizm1MNKhx4dd1fcd5aG%
.
Now we can issue an update statement to the table and verify.
update system.users set "hashedPassword" = '$2a$10$6Nxt.d8fxDcrJWZ6Y5QDZe8IecbBYMBCNmizm1MNKhx4dd1fcd5aG%' where username = 'roach';
A few caveats: we need to run this as a user with write access on the system.users
table. The hashedPassword
table will not be found unless you wrap the column name in double quotes "hashedPassword"
.
Now that we updated the password, we can try to authenticate as roach
with password changeme
.
Verify
cockroach sql --url 'postgresql://roach:changeme@clustername:26257/defaultdb?sslmode=verify-full...'
And we're in!
#
# Welcome to the CockroachDB SQL shell.
# All statements must be terminated by a semicolon.
# To exit, type: \q.
#
# Client version: CockroachDB CCL v21.1.9 (x86_64-apple-darwin19, built 2021/09/20 21:50:33, go1.15.14)
# Server version: CockroachDB CCL v21.1.6 (x86_64-unknown-linux-gnu, built 2021/07/20 15:30:39, go1.15.11)
warning: server version older than client! proceed with caution; some features may not be available.
# Cluster ID: c0854300-2c35-44b4-a7d1-2af71acd3e4c
#
# Enter \? for a brief introduction.
#
roach@free-tier.gcp-us-central1.cockroachlabs.cloud:26257/defaultdb>
This concludes our tutorial. I hope it serves you well.
Clean up
Since I'm using a perpetually free instance of Cockroach Cloud Free product, there's no clean-up except for either dropping the user or changing the password to something else. Happy coding!
Update
CockroachDB version 22.1 slated for the first half of this year will introduce a new password authentication method, SCRAM, which will/may change the approach in this tutorial. Aside from that, this method should still be applicable for any release to date.
Published at DZone with permission of Artem Ervits. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments