Skip to content

Commit c3d097f

Browse files
committed
STS integration, JWT auth and Stateless MCS
This commit changes the authentication mechanism between mcs and minio to an sts (security token service) schema using the user provided credentials, previously mcs was using master credentials. With that said in order for you to login to MCS as an admin your user must exists first on minio and have enough privileges to do administrative operations. ``` ./mc admin user add myminio alevsk alevsk12345 ``` ``` cat admin.json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "admin:*", "s3:*" ], "Resource": [ "arn:aws:s3:::*" ] } ] } ./mc admin policy add myminio admin admin.json ``` ``` ./mc admin policy set myminio admin user=alevsk ```
1 parent 0bcf88e commit c3d097f

28 files changed

+800
-300
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ assets:
2222

2323
test:
2424
@(go test -race -v github.com/minio/mcs/restapi/...)
25+
@(go test -race -v github.com/minio/mcs/pkg/auth)
2526

2627
coverage:
2728
@(go test -v -coverprofile=coverage.out github.com/minio/mcs/restapi/... && go tool cover -html=coverage.out && open coverage.html)

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/minio/mcs
33
go 1.14
44

55
require (
6+
github.com/dgrijalva/jwt-go v3.2.0+incompatible
67
github.com/elazarl/go-bindata-assetfs v1.0.0
78
github.com/go-openapi/errors v0.19.4
89
github.com/go-openapi/loads v0.19.5
@@ -12,6 +13,7 @@ require (
1213
github.com/go-openapi/swag v0.19.8
1314
github.com/go-openapi/validate v0.19.7
1415
github.com/jessevdk/go-flags v1.4.0
16+
github.com/json-iterator/go v1.1.9
1517
github.com/minio/cli v1.22.0
1618
github.com/minio/mc v0.0.0-20200415193718-68b638f2f96c
1719
github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab h1:9hlqghJl3e3HorXa6AD
390390
github.com/minio/minio v0.0.0-20200415191640-bde0f444dbab/go.mod h1:v8oQPMMaTkjDwp5cOz1WCElA4Ik+X+0y4On+VMk0fis=
391391
github.com/minio/minio-go/v6 v6.0.53 h1:8jzpwiOzZ5Iz7/goFWqNZRICbyWYShbb5rARjrnSCNI=
392392
github.com/minio/minio-go/v6 v6.0.53/go.mod h1:DIvC/IApeHX8q1BAMVCXSXwpmrmM+I+iBvhvztQorfI=
393+
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61 h1:pUSI/WKPdd77gcuoJkSzhJ4wdS8OMDOsOu99MtpXEQA=
393394
github.com/minio/parquet-go v0.0.0-20200414234858-838cfa8aae61/go.mod h1:4trzEJ7N1nBTd5Tt7OCZT5SEin+WiAXpdJ/WgPkESA8=
394395
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
395396
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=

pkg/auth/jwt.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package auth
18+
19+
import (
20+
"errors"
21+
"time"
22+
23+
jwtgo "github.com/dgrijalva/jwt-go"
24+
xjwt "github.com/minio/mcs/pkg/auth/jwt"
25+
"github.com/minio/minio-go/v6/pkg/credentials"
26+
"github.com/minio/minio/cmd"
27+
)
28+
29+
const (
30+
defaultInterNodeJWTExpiry = 3 * time.Hour
31+
)
32+
33+
var (
34+
errAuthentication = errors.New("Authentication failed, check your access credentials")
35+
errNoAuthToken = errors.New("JWT token missing")
36+
)
37+
38+
// IsJWTValid returns true or false depending if the provided jwt is valid or not
39+
func IsJWTValid(token string) bool {
40+
_, err := JWTAuthenticate(token)
41+
return err == nil
42+
}
43+
44+
// JWTAuthenticate takes a jwt, decode it, extract claims and validate the signature
45+
// returns claims after validation in the following format:
46+
//
47+
// type MapClaims struct {
48+
// AccessKeyID
49+
// SecretAccessKey
50+
// SessionToken
51+
// }
52+
func JWTAuthenticate(token string) (*xjwt.MapClaims, error) {
53+
if token == "" {
54+
return nil, errNoAuthToken
55+
}
56+
claims := xjwt.NewMapClaims()
57+
if err := xjwt.ParseWithClaims(token, claims); err != nil {
58+
return claims, errAuthentication
59+
}
60+
return claims, nil
61+
}
62+
63+
// NewJWTWithClaimsForClient generates a new jwt with claims based on the provided STS credentials
64+
func NewJWTWithClaimsForClient(credentials *credentials.Value, audience string) (string, error) {
65+
if credentials != nil {
66+
claims := xjwt.NewStandardClaims()
67+
claims.SetExpiry(cmd.UTCNow().Add(defaultInterNodeJWTExpiry))
68+
claims.SetAccessKeyID(credentials.AccessKeyID)
69+
claims.SetSecretAccessKey(credentials.SecretAccessKey)
70+
claims.SetSessionToken(credentials.SessionToken)
71+
claims.SetAudience(audience)
72+
73+
jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
74+
return jwt.SignedString([]byte(xjwt.GetHmacJWTSecret()))
75+
}
76+
return "", errors.New("provided credentials are empty")
77+
}

restapi/sessions/sessions.go renamed to pkg/auth/jwt/config.go

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,58 +14,16 @@
1414
// You should have received a copy of the GNU Affero General Public License
1515
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package sessions
17+
package jwt
1818

1919
import (
2020
"crypto/rand"
2121
"io"
2222
"strings"
23-
"sync"
2423

25-
mcCmd "github.com/minio/mc/cmd"
24+
"github.com/minio/minio/pkg/env"
2625
)
2726

28-
type Singleton struct {
29-
sessions map[string]*mcCmd.Config
30-
}
31-
32-
var instance *Singleton
33-
var once sync.Once
34-
35-
// Returns a Singleton instance that keeps the sessions
36-
func GetInstance() *Singleton {
37-
once.Do(func() {
38-
//build sessions hash
39-
sessions := make(map[string]*mcCmd.Config)
40-
41-
instance = &Singleton{
42-
sessions: sessions,
43-
}
44-
})
45-
return instance
46-
}
47-
48-
// The delete built-in function deletes the element with the specified key (m[key]) from the map.
49-
// If m is nil or there is no such element, delete is a no-op. https://golang.org/pkg/builtin/#delete
50-
func (s *Singleton) DeleteSession(sessionID string) {
51-
delete(s.sessions, sessionID)
52-
}
53-
54-
func (s *Singleton) NewSession(cfg *mcCmd.Config) string {
55-
// genereate random session id
56-
sessionID := RandomCharString(64)
57-
// store the cfg under that session id
58-
s.sessions[sessionID] = cfg
59-
return sessionID
60-
}
61-
62-
func (s *Singleton) ValidSession(sessionID string) bool {
63-
if _, ok := s.sessions[sessionID]; ok {
64-
return true
65-
}
66-
return false
67-
}
68-
6927
// Do not use:
7028
// https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go
7129
// It relies on math/rand and therefore not on a cryptographically secure RNG => It must not be used
@@ -93,3 +51,11 @@ func RandomCharString(n int) string {
9351
}
9452
return s.String()
9553
}
54+
55+
// defaultHmacJWTSecret will be used by default if application is not configured with a custom MCS_HMAC_JWT_SECRET secret
56+
var defaultHmacJWTSecret = RandomCharString(64)
57+
58+
// GetHmacJWTSecret returns the 64 bytes secret used for signing the generated JWT for the application
59+
func GetHmacJWTSecret() string {
60+
return env.Get(McsHmacJWTSecret, defaultHmacJWTSecret)
61+
}

pkg/auth/jwt/const.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// This file is part of MinIO Console Server
2+
// Copyright (c) 2020 MinIO, Inc.
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Affero General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Affero General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Affero General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package jwt
18+
19+
const (
20+
McsHmacJWTSecret = "MCS_HMAC_JWT_SECRET"
21+
)

0 commit comments

Comments
 (0)