2020-04-22 23:43:17 -07:00
|
|
|
// This file is part of MinIO Console Server
|
|
|
|
|
// Copyright (c) 2020 MinIO, Inc.
|
|
|
|
|
//
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
package auth
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"crypto/aes"
|
|
|
|
|
"crypto/cipher"
|
|
|
|
|
"crypto/rand"
|
|
|
|
|
"crypto/sha1"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"log"
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
"net/http"
|
2020-04-22 23:43:17 -07:00
|
|
|
"strings"
|
2020-07-09 12:24:01 -07:00
|
|
|
"time"
|
2020-04-22 23:43:17 -07:00
|
|
|
|
|
|
|
|
jwtgo "github.com/dgrijalva/jwt-go"
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
"github.com/go-openapi/swag"
|
2020-07-10 19:14:28 -07:00
|
|
|
"github.com/minio/mcs/models"
|
2020-04-22 23:43:17 -07:00
|
|
|
xjwt "github.com/minio/mcs/pkg/auth/jwt"
|
2020-07-25 12:25:21 -07:00
|
|
|
"github.com/minio/minio-go/v7/pkg/credentials"
|
2020-04-22 23:43:17 -07:00
|
|
|
uuid "github.com/satori/go.uuid"
|
|
|
|
|
"golang.org/x/crypto/pbkdf2"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
2020-05-18 21:55:54 -07:00
|
|
|
errAuthentication = errors.New("authentication failed, check your access credentials")
|
2020-04-22 23:43:17 -07:00
|
|
|
errNoAuthToken = errors.New("JWT token missing")
|
|
|
|
|
errReadingToken = errors.New("JWT internal data is malformed")
|
|
|
|
|
errClaimsFormat = errors.New("encrypted jwt claims not in the right format")
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// derivedKey is the key used to encrypt the JWT claims, its derived using pbkdf on MCS_PBKDF_PASSPHRASE with MCS_PBKDF_SALT
|
|
|
|
|
var derivedKey = pbkdf2.Key([]byte(xjwt.GetPBKDFPassphrase()), []byte(xjwt.GetPBKDFSalt()), 4096, 32, sha1.New)
|
|
|
|
|
|
|
|
|
|
// IsJWTValid returns true or false depending if the provided jwt is valid or not
|
|
|
|
|
func IsJWTValid(token string) bool {
|
|
|
|
|
_, err := JWTAuthenticate(token)
|
|
|
|
|
return err == nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 18:28:28 -07:00
|
|
|
// DecryptedClaims claims struct for decrypted credentials
|
2020-04-22 23:43:17 -07:00
|
|
|
type DecryptedClaims struct {
|
|
|
|
|
AccessKeyID string
|
|
|
|
|
SecretAccessKey string
|
|
|
|
|
SessionToken string
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
Actions []string
|
2020-04-22 23:43:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// JWTAuthenticate takes a jwt, decode it, extract claims and validate the signature
|
|
|
|
|
// if the jwt claims.Data is valid we proceed to decrypt the information inside
|
|
|
|
|
//
|
|
|
|
|
// returns claims after validation in the following format:
|
|
|
|
|
//
|
|
|
|
|
// type DecryptedClaims struct {
|
|
|
|
|
// AccessKeyID
|
|
|
|
|
// SecretAccessKey
|
|
|
|
|
// SessionToken
|
|
|
|
|
// }
|
|
|
|
|
func JWTAuthenticate(token string) (*DecryptedClaims, error) {
|
|
|
|
|
if token == "" {
|
|
|
|
|
return nil, errNoAuthToken
|
|
|
|
|
}
|
|
|
|
|
// initialize claims object
|
|
|
|
|
claims := xjwt.NewMapClaims()
|
|
|
|
|
// populate the claims object
|
|
|
|
|
if err := xjwt.ParseWithClaims(token, claims); err != nil {
|
|
|
|
|
return nil, errAuthentication
|
|
|
|
|
}
|
|
|
|
|
// decrypt the claims.Data field
|
|
|
|
|
claimTokens, err := decryptClaims(claims.Data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// we print decryption token error information for debugging purposes
|
|
|
|
|
log.Println(err)
|
|
|
|
|
// we return a generic error that doesn't give any information to attackers
|
|
|
|
|
return nil, errReadingToken
|
|
|
|
|
}
|
|
|
|
|
// claimsTokens contains the decrypted STS claims
|
|
|
|
|
return claimTokens, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewJWTWithClaimsForClient generates a new jwt with claims based on the provided STS credentials, first
|
|
|
|
|
// encrypts the claims and the sign them
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
func NewJWTWithClaimsForClient(credentials *credentials.Value, actions []string, audience string) (string, error) {
|
2020-04-22 23:43:17 -07:00
|
|
|
if credentials != nil {
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
encryptedClaims, err := encryptClaims(credentials.AccessKeyID, credentials.SecretAccessKey, credentials.SessionToken, actions)
|
2020-04-22 23:43:17 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
claims := xjwt.NewStandardClaims()
|
2020-07-09 12:24:01 -07:00
|
|
|
claims.SetExpiry(time.Now().UTC().Add(xjwt.GetMcsSTSAndJWTDurationTime()))
|
2020-04-22 23:43:17 -07:00
|
|
|
claims.SetSubject(uuid.NewV4().String())
|
|
|
|
|
claims.SetData(encryptedClaims)
|
|
|
|
|
claims.SetAudience(audience)
|
|
|
|
|
jwt := jwtgo.NewWithClaims(jwtgo.SigningMethodHS512, claims)
|
|
|
|
|
return jwt.SignedString([]byte(xjwt.GetHmacJWTSecret()))
|
|
|
|
|
}
|
|
|
|
|
return "", errors.New("provided credentials are empty")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// encryptClaims() receives the 3 STS claims, concatenate them and encrypt them using AES-GCM
|
|
|
|
|
// returns a base64 encoded ciphertext
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
func encryptClaims(accessKeyID, secretAccessKey, sessionToken string, actions []string) (string, error) {
|
|
|
|
|
payload := []byte(fmt.Sprintf("%s#%s#%s#%s", accessKeyID, secretAccessKey, sessionToken, strings.Join(actions, ",")))
|
2020-04-22 23:43:17 -07:00
|
|
|
ciphertext, err := encrypt(payload)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return base64.StdEncoding.EncodeToString(ciphertext), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decryptClaims() receives base64 encoded ciphertext, decode it, decrypt it (AES-GCM) and produces a *DecryptedClaims object
|
|
|
|
|
func decryptClaims(ciphertext string) (*DecryptedClaims, error) {
|
|
|
|
|
decoded, err := base64.StdEncoding.DecodeString(ciphertext)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Println(err)
|
|
|
|
|
return nil, errClaimsFormat
|
|
|
|
|
}
|
|
|
|
|
plaintext, err := decrypt(decoded)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Println(err)
|
|
|
|
|
return nil, errClaimsFormat
|
|
|
|
|
}
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
s := strings.Split(string(plaintext), "#")
|
2020-04-22 23:43:17 -07:00
|
|
|
// Validate that the decrypted string has the right format "accessKeyID:secretAccessKey:sessionToken"
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
if len(s) != 4 {
|
2020-04-22 23:43:17 -07:00
|
|
|
return nil, errClaimsFormat
|
|
|
|
|
}
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
accessKeyID, secretAccessKey, sessionToken, actions := s[0], s[1], s[2], s[3]
|
|
|
|
|
actionsList := strings.Split(actions, ",")
|
2020-04-22 23:43:17 -07:00
|
|
|
return &DecryptedClaims{
|
|
|
|
|
AccessKeyID: accessKeyID,
|
|
|
|
|
SecretAccessKey: secretAccessKey,
|
|
|
|
|
SessionToken: sessionToken,
|
ACL for mcs (#123)
This PR sets the initial version of the ACL for mcs, the idea behind
this is to start using the principle of least privileges when assigning
policies to users when creating users through mcs, currently mcsAdmin policy uses admin:*
and s3:* and by default a user with that policy will have access to everything, if want to limit
that we can create a policy with least privileges.
We need to start validating explicitly if users has acccess to an
specific endpoint based on IAM policy actions.
In this first version every endpoint (you can see it as a page to),
defines a set of well defined admin/s3 actions to work properly, ie:
```
// corresponds to /groups endpoint used by the groups page
var groupsActionSet = iampolicy.NewActionSet(
iampolicy.ListGroupsAdminAction,
iampolicy.AddUserToGroupAdminAction,
//iampolicy.GetGroupAdminAction,
iampolicy.EnableGroupAdminAction,
iampolicy.DisableGroupAdminAction,
)
// corresponds to /policies endpoint used by the policies page
var iamPoliciesActionSet = iampolicy.NewActionSet(
iampolicy.GetPolicyAdminAction,
iampolicy.DeletePolicyAdminAction,
iampolicy.CreatePolicyAdminAction,
iampolicy.AttachPolicyAdminAction,
iampolicy.ListUserPoliciesAdminAction,
)
```
With that said, for this initial version, now the sessions endpoint will
return a list of authorized pages to be render on the UI, on subsequent
prs we will add this verification of authorization via a server
middleware.
2020-05-18 18:03:06 -07:00
|
|
|
Actions: actionsList,
|
2020-04-22 23:43:17 -07:00
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Encrypt a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
|
|
|
|
func encrypt(plaintext []byte) ([]byte, error) {
|
|
|
|
|
block, _ := aes.NewCipher(derivedKey)
|
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
nonce := make([]byte, gcm.NonceSize())
|
|
|
|
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
cipherText := gcm.Seal(nonce, nonce, plaintext, nil)
|
|
|
|
|
return cipherText, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decrypts a blob of data using AEAD (AES-GCM) with a pbkdf2 derived key
|
|
|
|
|
func decrypt(data []byte) ([]byte, error) {
|
|
|
|
|
block, err := aes.NewCipher(derivedKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
gcm, err := cipher.NewGCM(block)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
nonceSize := gcm.NonceSize()
|
|
|
|
|
nonce, cipherText := data[:nonceSize], data[nonceSize:]
|
|
|
|
|
plaintext, err := gcm.Open(nil, nonce, cipherText, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return plaintext, nil
|
|
|
|
|
}
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
|
|
|
|
|
// GetTokenFromRequest returns a token from a http Request
|
|
|
|
|
// either defined on a cookie `token` or on Authorization header.
|
|
|
|
|
//
|
|
|
|
|
// Authorization Header needs to be like "Authorization Bearer <jwt_token>"
|
|
|
|
|
func GetTokenFromRequest(r *http.Request) (*string, error) {
|
|
|
|
|
// Get Auth token
|
|
|
|
|
var reqToken string
|
|
|
|
|
|
|
|
|
|
// Token might come either as a Cookie or as a Header
|
|
|
|
|
// if not set in cookie, check if it is set on Header.
|
|
|
|
|
tokenCookie, err := r.Cookie("token")
|
|
|
|
|
if err != nil {
|
|
|
|
|
headerToken := r.Header.Get("Authorization")
|
|
|
|
|
// reqToken should come as "Bearer <token>"
|
|
|
|
|
splitHeaderToken := strings.Split(headerToken, "Bearer")
|
|
|
|
|
if len(splitHeaderToken) <= 1 {
|
|
|
|
|
return nil, errNoAuthToken
|
|
|
|
|
}
|
|
|
|
|
reqToken = strings.TrimSpace(splitHeaderToken[1])
|
|
|
|
|
} else {
|
|
|
|
|
reqToken = strings.TrimSpace(tokenCookie.Value)
|
|
|
|
|
}
|
|
|
|
|
return swag.String(reqToken), nil
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-10 19:14:28 -07:00
|
|
|
func GetClaimsFromTokenInRequest(req *http.Request) (*models.Principal, error) {
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
sessionID, err := GetTokenFromRequest(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Perform decryption of the JWT, if MCS is able to decrypt the JWT that means a valid session
|
|
|
|
|
// was used in the first place to get it
|
|
|
|
|
claims, err := JWTAuthenticate(*sessionID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-07-10 19:14:28 -07:00
|
|
|
return &models.Principal{
|
|
|
|
|
AccessKeyID: claims.AccessKeyID,
|
|
|
|
|
Actions: claims.Actions,
|
|
|
|
|
SecretAccessKey: claims.SecretAccessKey,
|
|
|
|
|
SessionToken: claims.SessionToken,
|
|
|
|
|
}, nil
|
MCS service account authentication with Mkube (#166)
`MCS` will authenticate against `Mkube`using bearer tokens via HTTP
`Authorization` header. The user will provide this token once
in the login form, MCS will validate it against Mkube (list tenants) and
if valid will generate and return a new MCS sessions
with encrypted claims (the user Service account token will be inside the
JWT in the data field)
Kubernetes
The provided `JWT token` corresponds to the `Kubernetes service account`
that `Mkube` will use to run tasks on behalf of the
user, ie: list, create, edit, delete tenants, storage class, etc.
Development
If you are running mcs in your local environment and wish to make
request to `Mkube` you can set `MCS_M3_HOSTNAME`, if
the environment variable is not present by default `MCS` will use
`"http://m3:8787"`, additionally you will need to set the
`MCS_MKUBE_ADMIN_ONLY=on` variable to make MCS display the Mkube UI
Extract the Service account token and use it with MCS
For local development you can use the jwt associated to the `m3-sa`
service account, you can get the token running
the following command in your terminal:
```
kubectl get secret $(kubectl get serviceaccount m3-sa -o
jsonpath="{.secrets[0].name}") -o jsonpath="{.data.token}" | base64
--decode
```
Then run the mcs server
```
MCS_M3_HOSTNAME=http://localhost:8787 MCS_MKUBE_ADMIN_ONLY=on ./mcs
server
```
Self-signed certificates and Custom certificate authority for Mkube
If Mkube uses TLS with a self-signed certificate, or a certificate
issued by a custom certificate authority you can add those
certificates usinng the `MCS_M3_SERVER_TLS_CA_CERTIFICATE` env variable
````
MCS_M3_SERVER_TLS_CA_CERTIFICATE=cert1.pem,cert2.pem,cert3.pem ./mcs
server
````
2020-06-23 11:37:46 -07:00
|
|
|
}
|