Skip to content

Commit

Permalink
authn: add support for env vars for admin creds and secret
Browse files Browse the repository at this point in the history
- Added support for the following environment variables:
  * AIS_AUTHN_SECRET_KEY: Secret key for token signing
  * AIS_AUTHN_SU_NAME: Admin username
  * AIS_AUTHN_SU_PASS: Admin password
- Documentation updated accordingly

Signed-off-by: Abhishek Gaikwad <[email protected]>
  • Loading branch information
gaikwadabhishek committed Jul 22, 2024
1 parent 666d357 commit d50c223
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 51 deletions.
2 changes: 1 addition & 1 deletion ais/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (p *proxy) Run() error {
// startup sequence - see earlystart.go for the steps and commentary
p.bootstrap()

p.authn = newAuthManager()
p.authn = newAuthManager(config.Auth.Secret)

p.rproxy.init()

Expand Down
47 changes: 27 additions & 20 deletions ais/prxauth.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
// Package ais provides core functionality for the AIStore object storage.
/*
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
*/
package ais

import (
"fmt"
"net/http"
"os"
"sync"
"time"

"github.com/NVIDIA/aistore/api/apc"
"github.com/NVIDIA/aistore/api/authn"
"github.com/NVIDIA/aistore/api/env"
"github.com/NVIDIA/aistore/cmd/authn/tok"
"github.com/NVIDIA/aistore/cmn"
"github.com/NVIDIA/aistore/cmn/cos"
Expand All @@ -32,54 +34,62 @@ type (
// Authn sends these tokens to primary for broadcasting
revokedTokens map[string]bool
version int64
// signing key secret
secret string
}
)

/////////////////
// authManager //
/////////////////

func newAuthManager() *authManager {
return &authManager{tkList: make(tkList), revokedTokens: make(map[string]bool), version: 1}
func newAuthManager(secret string) *authManager {
// First check for the secret key in the environment variable
// and if not found, falls back to the config's secret key.
if envSecret := os.Getenv(env.AuthN.SecretKey); envSecret != "" {
secret = envSecret
}
return &authManager{tkList: make(tkList), revokedTokens: make(map[string]bool), version: 1, secret: secret}
}

// Add tokens to list of invalid ones. After that it cleans up the list
// from expired tokens
// Add tokens to the list of invalid ones and clean up the list from expired tokens.
func (a *authManager) updateRevokedList(newRevoked *tokenList) (allRevoked *tokenList) {
a.Lock()
defer a.Unlock()

switch {
case newRevoked.Version == 0: // manually revoked
case newRevoked.Version == 0: // Manually revoked tokens
a.version++
case newRevoked.Version > a.version:
a.version = newRevoked.Version
default:
nlog.Errorf("Current token list v%d is greater than received v%d", a.version, newRevoked.Version)
a.Unlock()
return
}
// add new

// Add new revoked tokens and remove them from the valid token list.
for _, token := range newRevoked.Tokens {
a.revokedTokens[token] = true
delete(a.tkList, token)
}

allRevoked = &tokenList{
Tokens: make([]string, 0, len(a.revokedTokens)),
Version: a.version,
}
var (
now = time.Now()
secret = cmn.GCO.Get().Auth.Secret
)

// Clean up expired tokens from the revoked list.
now := time.Now()

for token := range a.revokedTokens {
tk, err := tok.DecryptToken(token, secret)
tk, err := tok.DecryptToken(token, a.secret)
debug.AssertNoErr(err)
if tk.Expires.Before(now) {
delete(a.revokedTokens, token)
} else {
allRevoked.Tokens = append(allRevoked.Tokens, token)
}
}
a.Unlock()
if len(allRevoked.Tokens) == 0 {
allRevoked = nil
}
Expand Down Expand Up @@ -123,11 +133,8 @@ func (a *authManager) validateToken(token string) (tk *tok.Token, err error) {
func (a *authManager) validateAddRm(token string, now time.Time) (*tok.Token, error) {
tk, ok := a.tkList[token]
if !ok || tk == nil {
var (
err error
secret = cmn.GCO.Get().Auth.Secret
)
if tk, err = tok.DecryptToken(token, secret); err != nil {
var err error
if tk, err = tok.DecryptToken(token, a.secret); err != nil {
nlog.Errorln(err)
return nil, tok.ErrInvalidToken
}
Expand Down Expand Up @@ -175,7 +182,7 @@ func (p *proxy) validateSecret(w http.ResponseWriter, r *http.Request) {
return
}
cksum := cos.NewCksumHash(cos.ChecksumSHA256)
cksum.H.Write([]byte(cmn.GCO.Get().Auth.Secret))
cksum.H.Write([]byte(p.authn.secret))
cksum.Finalize()

cluConf := &authn.ServerConf{}
Expand Down
6 changes: 5 additions & 1 deletion api/env/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ var (
TTL string
UseHTTPS string
AdminPassword string
AdminUsername string
SecretKey string
}{
Enabled: "AIS_AUTHN_ENABLED",
URL: "AIS_AUTHN_URL",
Expand All @@ -29,6 +31,8 @@ var (
Port: "AIS_AUTHN_PORT",
TTL: "AIS_AUTHN_TTL",
UseHTTPS: "AIS_AUTHN_USE_HTTPS",
AdminPassword: "AIS_AUTHN_ADMIN_PASSWORD",
SecretKey: "AIS_AUTHN_SECRET_KEY",
AdminUsername: "AIS_AUTHN_SU_NAME",
AdminPassword: "AIS_AUTHN_SU_PASS",
}
)
4 changes: 1 addition & 3 deletions cmd/authn/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"github.com/NVIDIA/aistore/cmn/nlog"
)

const secretKeyPodEnv = "SECRETKEY" // via https://kubernetes.io/docs/concepts/configuration/secret

var (
build string
buildtime string
Expand Down Expand Up @@ -73,7 +71,7 @@ func main() {
cos.ExitLogf("Failed to load configuration from %q: %v", configPath, err)
}
Conf.Init()
if val := os.Getenv(secretKeyPodEnv); val != "" {
if val := os.Getenv(env.AuthN.SecretKey); val != "" {
Conf.SetSecret(&val)
}
if err := updateLogOptions(); err != nil {
Expand Down
9 changes: 6 additions & 3 deletions cmd/authn/mgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,10 @@ func initializeDB(driver kvdb.Driver) error {
if err := driver.Set(rolesCollection, authn.AdminRole, role); err != nil {
return err
}

userName := os.Getenv(env.AuthN.AdminUsername)
if userName == "" {
userName = adminUserID
}
// Get the admin password from the environment variable or use the default
password := os.Getenv(env.AuthN.AdminPassword)
if password == "" {
Expand All @@ -508,10 +511,10 @@ func initializeDB(driver kvdb.Driver) error {

// Create the admin user
su := &authn.User{
ID: adminUserID,
ID: userName,
Password: encryptPassword(password),
Roles: []*authn.Role{role},
}

return driver.Set(usersCollection, adminUserID, su)
return driver.Set(usersCollection, userName, su)
}
2 changes: 1 addition & 1 deletion deploy/dev/local/aisnode_config.fspaths.sh
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ cat > $AIS_CONF_FILE <<EOL
"enabled": true
},
"auth": {
"secret": "$AIS_SECRET_KEY",
"secret": "$AIS_AUTHN_SECRET_KEY",
"enabled": ${AIS_AUTHN_ENABLED:-false}
},
"keepalivetracker": {
Expand Down
2 changes: 1 addition & 1 deletion deploy/dev/local/authn_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ cat > "$AIS_AUTHN_CONF_DIR/authn.json" <<EOL
}
},
"auth": {
"secret": "$AIS_SECRET_KEY",
"secret": "$AIS_AUTHN_SECRET_KEY",
"expiration_time": "${AIS_AUTHN_TTL:-24h}"
},
"timeout": {
Expand Down
2 changes: 1 addition & 1 deletion deploy/dev/local/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ if $AIS_USE_HTTPS; then
fi
LOG_ROOT="${LOG_ROOT:-/tmp/ais}${NEXT_TIER}"
#### Authentication setup #########
AIS_SECRET_KEY="${AIS_SECRET_KEY:-aBitLongSecretKey}"
AIS_AUTHN_SECRET_KEY="${AIS_AUTHN_SECRET_KEY:-aBitLongSecretKey}"
AIS_AUTHN_ENABLED="${AIS_AUTHN_ENABLED:-false}"
AIS_AUTHN_SU_NAME="${AIS_AUTHN_SU_NAME:-admin}"
AIS_AUTHN_SU_PASS="${AIS_AUTHN_SU_PASS:-admin}"
Expand Down
24 changes: 13 additions & 11 deletions docs/authn.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,17 +176,19 @@ Further references:
Environment variables used by the deployment script to set up the AuthN server:
| Variable | Default Value | Description |
|----------------------|---------------------|---------------------------------------------------------------|
| AIS_SECRET_KEY | `aBitLongSecretKey` | A secret key to sign tokens |
| AIS_AUTHN_ENABLED | `false` | Set it to `true` to enable AuthN server and token-based access in AIStore proxy |
| AIS_AUTHN_PORT | `52001` | Port on which AuthN listens to requests |
| AIS_AUTHN_TTL | `24h` | A token expiration time. Can be set to 0 which means "no expiration time" |
| AIS_AUTHN_USE_HTTPS | `false` | Enable HTTPS for AuthN server. If `true`, AuthN server requires also `AIS_SERVER_CRT` and `AIS_SERVER_KEY` to be set |
| AIS_SERVER_CRT | `` | OpenSSL certificate. Optional: set it only when secure HTTP is enabled |
| AIS_SERVER_KEY | `` | OpenSSL key. Optional: set it only when secure HTTP is enabled |
All variables can be set at AIStore cluster deployment.
| Variable | Default Value | Description |
|----------------------|---------------------|-------------------------------------------------------------------------------------------------|
| `AIS_AUTHN_SECRET_KEY` | `aBitLongSecretKey` | Secret key used to sign tokens |
| `AIS_AUTHN_ENABLED` | `false` | Enable AuthN server and token-based access in AIStore proxy (`true` to enable) |
| `AIS_AUTHN_PORT` | `52001` | Port on which AuthN listens to requests |
| `AIS_AUTHN_TTL` | `24h` | Token expiration time. Can be set to `0` for no expiration |
| `AIS_AUTHN_USE_HTTPS` | `false` | Enable HTTPS for AuthN server. If `true`, requires `AIS_SERVER_CRT` and `AIS_SERVER_KEY` to be set |
| `AIS_SERVER_CRT` | `""` | OpenSSL certificate. Required when `AIS_AUTHN_USE_HTTPS` is `true` |
| `AIS_SERVER_KEY` | `""` | OpenSSL key. Required when `AIS_AUTHN_USE_HTTPS` is `true` |
| `AIS_AUTHN_SU_NAME` | `admin` | Superuser (admin) name for AuthN |
| `AIS_AUTHN_SU_PASS` | `admin` | Superuser (admin) password for AuthN |
All variables can be set at AIStore cluster deployment and will override values in the config.
Example of starting a cluster with AuthN enabled:
```sh
Expand Down
20 changes: 11 additions & 9 deletions docs/environment-vars.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,17 @@ AIStore Authentication Server (**AuthN**) provides OAuth 2.0 compliant [JSON Web

AuthN supports multiple AIS clusters; in fact, there's no limit on the number of clusters a given AuthN instance can provide authentication and access control service for.

| name | comment |
| ---- | ------- |
| `AIS_AUTHN_ENABLED` | aistore cluster itself must "know" whether it is being authenticated; see usage and references below |
| `AIS_AUTHN_CONF_DIR` | AuthN server configuration directory, e.g. `"$HOME/.config/ais/authn` |
| `AIS_AUTHN_LOG_DIR` | usage: deployment scripts and integration tests |
| `AIS_AUTHN_LOG_LEVEL` | ditto |
| `AIS_AUTHN_PORT` | can be used to override `52001` default |
| `AIS_AUTHN_TTL` | authentication token expiration time; 0 (zero) means "never expires" |
| `AIS_AUTHN_USE_HTTPS` | when true, tells a starting-up AuthN to use HTTPS |
| Variable | Default Value | Description |
|----------------------|---------------------|-------------------------------------------------------------------------------------------------|
| `AIS_AUTHN_SECRET_KEY` | `aBitLongSecretKey` | Secret key used to sign tokens |
| `AIS_AUTHN_ENABLED` | `false` | Enable AuthN server and token-based access in AIStore proxy (`true` to enable) |
| `AIS_AUTHN_PORT` | `52001` | Port on which AuthN listens to requests |
| `AIS_AUTHN_TTL` | `24h` | Token expiration time. Can be set to `0` for no expiration |
| `AIS_AUTHN_USE_HTTPS` | `false` | Enable HTTPS for AuthN server. If `true`, requires `AIS_SERVER_CRT` and `AIS_SERVER_KEY` to be set |
| `AIS_SERVER_CRT` | `""` | OpenSSL certificate. Required when `AIS_AUTHN_USE_HTTPS` is `true` |
| `AIS_SERVER_KEY` | `""` | OpenSSL key. Required when `AIS_AUTHN_USE_HTTPS` is `true` |
| `AIS_AUTHN_SU_NAME` | `admin` | Superuser (admin) name for AuthN |
| `AIS_AUTHN_SU_PASS` | `admin` | Superuser (admin) password for AuthN |

Separately, there's also client-side AuthN environment that includes:

Expand Down

0 comments on commit d50c223

Please sign in to comment.