Access Control Lists
dgraph acl
command is deprecated and will be removed in a future release. ACL changes can be made by using the /admin
GraphQL endpoint on any Alpha node.
Access Control List (ACL) provides access protection to your data stored in Dgraph. When the ACL feature is enabled, a client, e.g. dgo or dgraph4j, must authenticate with a username and password before executing any transactions, and is only allowed to access the data permitted by the ACL rules.
Enable enterprise ACL feature
-
Generate a data encryption key that is 32 bytes long:
tr -dc 'a-zA-Z0-9' < /dev/urandom | dd bs=1 count=32 of=enc_key_file
LC_CTYPE=C; tr -dc 'a-zA-Z0-9' < /dev/urandom | dd bs=1 count=32 of=enc_key_file
.
-
To view the secret key value use
cat enc_key_file
. -
Create a plain text file named
hmac_secret_file
, and store a randomly generated<SECRET KEY VALUE>
in it. The secret key is used by Dgraph Alpha nodes to sign JSON Web Tokens (JWT).echo '<SECRET KEY VALUE>' > hmac_secret_file
-
Start all the Dgraph Alpha nodes in your cluster with the option
--acl secret-file="/path/to/secret"
, and make sure that they are all using the same secret key file created in Step 1. Alternatively, you can store the secret in Hashicorp Vault.dgraph alpha --acl "secret-file=/path/to/secret" --security "whitelist=<permitted-ip-addresses>"
--acl secret-file="/path/to/secret"
and --security "whitelist=<permitted-ip-addresses>"
, you can also configure Dgraph using a configuration file (config.yaml
, config.json
). You can also use environment variables, i.e. DGRAPH_ALPHA_ACL="secret-file=</path/to/secret>"
and DGRAPH_ALPHA_SECURITY="whitelist=<permitted-ip-addresses>"
. See Config for more information in general about configuring Dgraph.
Example using Dgraph CLI
Here is an example that starts a Dgraph Zero node and a Dgraph Alpha node with the ACL feature turned on. You can run these commands in a separate terminal tab:
## Create ACL secret key file with 32 ASCII characters
echo '<SECRET KEY VALUE>' > hmac_secret_file
## Start Dgraph Zero in different terminal tab or window
dgraph zero --my=localhost:5080 --replicas 1 --raft idx=1
## Start Dgraph Alpha in different terminal tab or window
dgraph alpha --my=localhost:7080 --zero=localhost:5080 \
--acl secret-file="./hmac_secret_file" \
--security whitelist="10.0.0.0/8,172.0.0.0/8,192.168.0.0/16"
Example using Docker Compose
If you are using Docker Compose, you can set up a sample Dgraph cluster using this docker-compose.yaml
configuration:
version: '3.5'
services:
alpha1:
command: dgraph alpha --my=alpha1:7080 --zero=zero1:5080
container_name: alpha1
environment:
DGRAPH_ALPHA_ACL: secret-file=/dgraph/acl/hmac_secret_file
DGRAPH_ALPHA_SECURITY: whitelist=10.0.0.0/8,172.0.0.0/8,192.168.0.0/16
image: dgraph/dgraph:main
ports:
- "8080:8080"
volumes:
- ./hmac_secret_file:/dgraph/acl/hmac_secret_file
zero1:
command: dgraph zero --my=zero1:5080 --replicas 1 --raft idx=1
container_name: zero1
image: dgraph/dgraph:main
You can run this with:
## Create ACL secret key file with 32 ASCII characters
echo '<SECRET KEY VALUE>' > hmac_secret_file
## Start Docker Compose
docker-compose up
Example using Kubernetes Helm Chart
If you deploy Dgraph on Kubernetes, you can configure the ACL feature using the Dgraph Helm Chart.
The first step is to encode the secret with base64:
## encode a secret without newline character and copy to the clipboard
printf '<SECRET KEY VALUE>' | base64
The next step is that we need to create a Helm chart config values file, e.g. dgraph_values.yaml
. We want to copy the results of encoded secret as paste this into the hmac_secret_file
like the example below:
## dgraph_values.yaml
alpha:
acl:
enabled: true
file:
hmac_secret_file: <SECRET KEY VALUE>
configFile:
config.yaml: |
acl:
secret_file: /dgraph/acl/hmac_secret_file
security:
whitelist: 10.0.0.0/8,172.0.0.0/8,192.168.0.0/16
Now with the Helm chart config values created, we can deploy Dgraph:
helm repo add "dgraph" https://charts.dgraph.io
helm install "my-release" --values ./dgraph_values.yaml dgraph/dgraph
Storing ACL secret in Hashicorp Vault
You can save the ACL secret on Hashicorp Vault server instead of saving the secret on the local file system.
Configuring a Hashicorp Vault Server
Do the following to set up on the Hashicorp Vault server for use with Dgraph:
- Ensure that the Vault server is accessible from Dgraph Alpha and configured using URL
http://fqdn[ip]:port
. - Enable AppRole Auth method and enable KV Secrets Engine.
- Save the 256-bits (32 ASCII characters) long ACL secret in a KV Secret path (K/V Version 1 or K/V Version 2). For example, you can upload this below to KV Secrets Engine Version 2 path of
secret/data/dgraph/alpha
:{ "options": { "cas": 0 }, "data": { "hmac_secret_file": "<SECRET KEY VALUE>" } }
- Create or use a role with an attached policy that grants access to the secret. For example, the following policy would grant access to
secret/data/dgraph/alpha
:path "secret/data/dgraph/*" { capabilities = [ "read", "update" ] }
- Using the
role_id
generated from the previous step, create a correspondingsecret_id
, and copy therole_id
andsecret_id
over to local files, like./dgraph/vault/role_id
and./dgraph/vault/secret_id
, that will be used by Dgraph Alpha nodes.
acl-field
option can be defined using acl-format
with the values base64
(default) or raw
.
Example using Dgraph CLI with Hashicorp Vault configuration
Here is an example of using Dgraph with a Vault server that holds the secret key:
## Start Dgraph Zero in different terminal tab or window
dgraph zero --my=localhost:5080 --replicas 1 --raft "idx=1"
## Start Dgraph Alpha in different terminal tab or window
dgraph alpha \
--security whitelist="10.0.0.0/8,172.0.0.0/8,192.168.0.0/16" \
--vault addr="http://localhost:8200";acl-field="hmac_secret_file";acl-format="raw";path="secret/data/dgraph/alpha";role-id-file="./role_id";secret-id-file="./secret_id"
Example using Docker Compose with Hashicorp Vault configuration
If you are using Docker Compose, you can set up a sample Dgraph cluster using this docker-compose.yaml
configuration:
version: '3.5'
services:
alpha1:
command: dgraph alpha --my=alpha1:7080 --zero=zero1:5080
container_name: alpha1
environment:
DGRAPH_ALPHA_VAULT: addr=http://vault:8200;acl-field=hmac_secret_file;acl-format=raw;path=secret/data/dgraph/alpha;role-id-file=/dgraph/vault/role_id;secret-id-file=/dgraph/vault/secret_id
DGRAPH_ALPHA_SECURITY: whitelist=10.0.0.0/8,172.0.0.0/8,192.168.0.0/16
image: dgraph/dgraph:main
ports:
- "8080:8080"
volumes:
- ./role_id:/dgraph/vault/role_id
- ./secret_id:/dgraph/vault/secret_id
zero1:
command: dgraph zero --my=zero1:5080 --replicas 1 --raft idx=1
container_name: zero1
image: dgraph/dgraph:main
In this example, you will also need to configure a Hashicorp Vault service named vault
in the above docker-compose.yaml
, and then run through this sequence:
- Launch
vault
service:docker-compose up --detach vault
- Unseal and Configure
vault
with the required prerequisites (see Configuring a Hashicorp Vault Server). - Save role-id and secret-id as
./role_id
andsecret_id
- Launch Dgraph Zero and Alpha:
docker-compose up --detach
Example using Kubernetes Helm Chart with Hashicorp Vault configuration
If you deploy Dgraph on Kubernetes, you can configure the ACL feature using the Dgraph Helm Chart.
The next step is that we need to create a Helm chart config values file, such as dgraph_values.yaml
.
## dgraph_values.yaml
alpha:
configFile:
config.yaml: |
vault:
addr: http://vault-headless.default.svc.cluster.local:9200
acl_field: hmac_secret_file
acl_format: raw
path: secret/data/dgraph/alpha
role_id_file: /dgraph/vault/role_id
secret_id_file: /dgraph/vault/secret_id
security:
whitelist: 10.0.0.0/8,172.0.0.0/8,192.168.0.0/16‘
To set up this chart, the Hashicorp Vault service must be installed and available. You can use the Hashicorp Vault Helm Chart and configure it to auto unseal so that the service is immediately available after deployment.
Accessing secured Dgraph
Before managing users and groups and configuring ACL rules, you will need to login in order to get a token that is needed to access Dgraph. You will use this token with the X-Dgraph-AccessToken
header field.
Logging In
To login, send a POST request to /admin
with the GraphQL mutation. For example, to log in as the root user groot
:
mutation {
login(userId: "groot", password: "password") {
response {
accessJWT
refreshJWT
}
}
}
Response:
{
"data": {
"accessJWT": "<accessJWT>",
"refreshJWT": "<refreshJWT>"
}
}
Access Token
The response includes the access and refresh JWTs which are used for the authentication itself and refreshing the authentication token, respectively. Save the JWTs from the response for later HTTP requests.
You can run authenticated requests by passing the access JWT to a request via the X-Dgraph-AccessToken
header. Add the header X-Dgraph-AccessToken
with the accessJWT
value which you got in the login response in the GraphQL tool which you’re using to make the request.
For example, if you were using the GraphQL Playground, you would add this in the headers section:
{ "X-Dgraph-AccessToken" : "<accessJWT>" }
And in the main code section, you can add a mutation, such as:
mutation {
addUser(input: [{ name: "alice", password: "whiterabbit" }]) {
user {
name
}
}
}
Refresh Token
The refresh token can be used in the /admin
POST GraphQL mutation to receive new access and refresh JWTs, which is useful to renew the authenticated session once the ACL access TTL expires (controlled by Dgraph Alpha’s flag --acl_access_ttl
which is set to 6h0m0s by default).
mutation {
login(
userId: "groot"
password: "password"
refreshToken: "<refreshJWT>"
) {
response {
accessJWT
refreshJWT
}
}
}
Login using a client
With ACL configured, you need to log in as a user to access data protected by ACL rules. You can do this using the client’s .login(USER_ID, USER_PASSWORD)
method.
Here are some code samples using a client:
- Go (dgo client): example
acl_over_tls_test.go
(here) - Java (dgraph4j): example
AclTest.java
(here)
Login using curl
If you are using curl
from the command line, you can use the following with the above login mutation saved to login.graphql
:
## Login and save results
JSON_RESULT=$(curl http://localhost:8080/admin --silent --request POST \
--header "Content-Type: application/graphql" \
--upload-file login.graphql
)
## Extracting a token using GNU grep, perl, the silver searcher, or jq
TOKEN=$(grep -oP '(?<=accessJWT":")[^"]*' <<< $JSON_RESULT)
TOKEN=$(perl -wln -e '/(?<=accessJWT":")[^"]*/ and print $&;' <<< $JSON_RESULT)
TOKEN=$(ag -o '(?<=accessJWT":")[^"]*' <<< $JSON_RESULT)
TOKEN=$(jq -r '.data.login.response.accessJWT' <<< $JSON_RESULT)
## Run a GraphQL query using the token
curl http://localhost:8080/admin --silent --request POST \
--header "Content-Type: application/graphql" \
--header "X-Dgraph-AccessToken: $TOKEN" \
--upload-file some_other_query.graphql
User and group administration
The default configuration comes with a user groot
, with a password of password
. The groot
user is part of administrative group called guardians
that have access to everything. You can add more users to the guardians
group as needed.
Reset the root password
You can reset the root password like this example:
mutation {
updateUser(
input: {
filter: { name: { eq: "groot" } }
set: { password: "$up3r$3cr3t1337p@$$w0rd" }
}
) {
user {
name
}
}
}
Create a regular user
To create a user alice
, with password whiterabbit
, you should execute the following GraphQL mutation:
mutation {
addUser(input: [{name: "alice", password: "whiterabbit"}]) {
user {
name
}
}
}
Create a group
To create a group dev
, you should execute:
mutation {
addGroup(input: [{name: "dev"}]) {
group {
name
users {
name
}
}
}
}
Assign a user to a group
To assign the user alice
to both the group dev
and the group sre
, the mutation should be
mutation {
updateUser(
input: {
filter: { name: { eq: "alice" } }
set: { groups: [{ name: "dev" }, { name: "sre" }] }
}
) {
user {
name
groups {
name
}
}
}
}
Remove a user from a group
To remove alice
from the dev
group, the mutation should be
mutation {
updateUser(
input: {
filter: { name: { eq: "alice" } }
remove: { groups: [{ name: "dev" }] }
}
) {
user {
name
groups {
name
}
}
}
}
Delete a User
To delete the user alice
, you should execute
mutation {
deleteUser(filter: { name: { eq: "alice" } }) {
msg
numUids
}
}
Delete a Group
To delete the group sre
, the mutation should be
mutation {
deleteGroup(filter: { name: { eq: "sre" } }) {
msg
numUids
}
}
ACL rules configuration
You can set up ACL rules using the Dgraph Ratel UI or by using a GraphQL tool, such as Insomnia, GraphQL Playground, GraphiQL, etc. You can set the permissions on a predicate for the group using a pattern similar to the UNIX file permission conventions shown below:
Permission | Value | Binary |
---|---|---|
READ |
4 |
100 |
WRITE |
2 |
010 |
MODIFY |
1 |
001 |
READ + WRITE |
6 |
110 |
READ + WRITE + MODIFY |
7 |
111 |
These permissions represent the following:
READ
- group has permission to read read the predicateWRITE
- group has permission to write or update the predicateMODIFY
- group has permission to change the predicate’s schema
The following examples will grant full permissions to predicates to the group dev
. If there are no rules for
a predicate, the default behavior is to block all (READ
, WRITE
and MODIFY
) operations.
Assign predicate permissions to a group
Here we assign a permission rule for the friend
predicate to the group:
mutation {
updateGroup(
input: {
filter: { name: { eq: "dev" } }
set: { rules: [{ predicate: "friend", permission: 7 }] }
}
) {
group {
name
rules {
permission
predicate
}
}
}
}
In case you have reverse edges, they have to be given the permission to the group as well
mutation {
updateGroup(
input: {
filter: { name: { eq: "dev" } }
set: { rules: [{ predicate: "~friend", permission: 7 }] }
}
) {
group {
name
rules {
permission
predicate
}
}
}
}
In some cases, it may be desirable to manage permissions for all the predicates together rather than individual ones. This can be achieved using the dgraph.all
keyword.
The following example provides read+write
access to the dev
group over all the predicates of a given namespace using the dgraph.all
keyword.
mutation {
updateGroup(
input: {
filter: { name: { eq: "dev" } }
set: { rules: [{ predicate: "dgraph.all", permission: 6 }] }
}
) {
group {
name
rules {
permission
predicate
}
}
}
}
dev
is the union of permissions from dgraph.all
and permissions for a specific predicate name
. So if the group is assigned READ
permission for dgraph.all
and WRITE
permission for predicate name
it will have both, READ
and WRITE
permissions for the name
predicate, as a result of the union.
Remove a rule from a group
To remove a rule or rules from the group dev
, the mutation should be:
mutation {
updateGroup(
input: {
filter: { name: { eq: "dev" } }
remove: { rules: [ "friend", "~friend" ] }
}
) {
group {
name
rules {
predicate
permission
}
}
}
}
Querying users and groups
You can set up ACL rules using the Dgraph Ratel UI or by using a GraphQL tool, such as Insomnia, GraphQL Playground, GraphiQL, etc. The permissions can be set on a predicate for the group using using pattern similar to the UNIX file permission convention:
You can query and get information for users and groups. These sections show output that will show the user alice
and the dev
group along with rules for friend
and ~friend
predicates.
Query for users
Let’s query for the user alice
:
query {
queryUser(filter: { name: { eq: "alice" } }) {
name
groups {
name
}
}
}
The output should show the groups that the user has been added to, e.g.
{
"data": {
"queryUser": [
{
"name": "alice",
"groups": [
{
"name": "dev"
}
]
}
]
}
}
Get user information
We can obtain information about a user with the following query:
query {
getUser(name: "alice") {
name
groups {
name
}
}
}
The output should show the groups that the user has been added to, e.g.
{
"data": {
"getUser": {
"name": "alice",
"groups": [
{
"name": "dev"
}
]
}
}
}
Query for groups
Let’s query for the dev
group:
query {
queryGroup(filter: { name: { eq: "dev" } }) {
name
users {
name
}
rules {
permission
predicate
}
}
}
The output should include the users in the group as well as the permissions, the group’s ACL rules, e.g.
{
"data": {
"queryGroup": [
{
"name": "dev",
"users": [
{
"name": "alice"
}
],
"rules": [
{
"permission": 7,
"predicate": "friend"
},
{
"permission": 7,
"predicate": "~friend"
}
]
}
]
}
}
Get group information
To check the dev
group information:
query {
getGroup(name: "dev") {
name
users {
name
}
rules {
permission
predicate
}
}
}
The output should include the users in the group as well as the permissions, the group’s ACL rules, e.g.
{
"data": {
"getGroup": {
"name": "dev",
"users": [
{
"name": "alice"
}
],
"rules": [
{
"permission": 7,
"predicate": "friend"
},
{
"permission": 7,
"predicate": "~friend"
}
]
}
}
}
Reset Groot Password
If you have forgotten the password to the groot
user, then you may reset the groot
password (or
the password for any user) by following these steps.
- Stop Dgraph Alpha.
- Turn off ACLs by removing the
--acl_hmac_secret
config flag in the Alpha config. This leaves the Alpha open with no ACL rules, so be sure to restrict access, including stopping request traffic to this Alpha. - Start Dgraph Alpha.
- Connect to Dgraph Alpha using Ratel and run the following upsert mutation to update the
groot
password tonewpassword
(choose your own secure password):upsert { query { groot as var(func: eq(dgraph.xid, "groot")) } mutation { set { uid(groot) <dgraph.password> "newpassword" . } } }
- Restart Dgraph Alpha with ACLs turned on by setting the
--acl_hmac_secret
config flag. - Login as groot with your new password.