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 ````
This commit is contained in:
@@ -61,18 +61,25 @@ func registerLoginHandlers(api *operations.McsAPI) {
|
||||
}
|
||||
return user_api.NewLoginOauth2AuthCreated().WithPayload(loginResponse)
|
||||
})
|
||||
api.UserAPILoginMkubeHandler = user_api.LoginMkubeHandlerFunc(func(params user_api.LoginMkubeParams) middleware.Responder {
|
||||
loginResponse, err := getLoginMkubeResponse(params.Body)
|
||||
if err != nil {
|
||||
return user_api.NewLoginMkubeDefault(401).WithPayload(&models.Error{Code: 401, Message: swag.String(err.Error())})
|
||||
}
|
||||
return user_api.NewLoginMkubeCreated().WithPayload(loginResponse)
|
||||
})
|
||||
}
|
||||
|
||||
// login performs a check of minioCredentials against MinIO, generates some claims and returns the jwt
|
||||
// login performs a check of mcsCredentials against MinIO, generates some claims and returns the jwt
|
||||
// for subsequent authentication
|
||||
func login(credentials MCSCredentials, actions []string) (*string, error) {
|
||||
// try to obtain minioCredentials,
|
||||
// try to obtain mcsCredentials,
|
||||
tokens, err := credentials.Get()
|
||||
if err != nil {
|
||||
log.Println("error authenticating user", err)
|
||||
return nil, errInvalidCredentials
|
||||
}
|
||||
// if we made it here, the minioCredentials work, generate a jwt with claims
|
||||
// if we made it here, the mcsCredentials work, generate a jwt with claims
|
||||
jwt, err := auth.NewJWTWithClaimsForClient(&tokens, actions, getMinIOServer())
|
||||
if err != nil {
|
||||
log.Println("error authenticating user", err)
|
||||
@@ -115,7 +122,7 @@ func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, error) {
|
||||
log.Println("error login:", err)
|
||||
return nil, errInvalidCredentials
|
||||
}
|
||||
credentials := mcsCredentials{minioCredentials: creds}
|
||||
credentials := mcsCredentials{mcsCredentials: creds}
|
||||
// obtain the current policy assigned to this user
|
||||
// necessary for generating the list of allowed endpoints
|
||||
userInfo, err := adminClient.getUserInfo(ctx, *lr.AccessKey)
|
||||
@@ -127,7 +134,7 @@ func getLoginResponse(lr *models.LoginRequest) (*models.LoginResponse, error) {
|
||||
// by default every user starts with an empty array of available actions
|
||||
// therefore we would have access only to pages that doesn't require any privilege
|
||||
// ie: service-account page
|
||||
actions := []string{}
|
||||
var actions []string
|
||||
// if a policy is assigned to this user we parse the actions from there
|
||||
if policy != nil {
|
||||
actions = acl.GetActionsStringFromPolicy(policy)
|
||||
@@ -148,7 +155,9 @@ func getLoginDetailsResponse() (*models.LoginDetails, error) {
|
||||
ctx := context.Background()
|
||||
loginStrategy := models.LoginDetailsLoginStrategyForm
|
||||
redirectURL := ""
|
||||
if oauth2.IsIdpEnabled() {
|
||||
if acl.GetOperatorOnly() {
|
||||
loginStrategy = models.LoginDetailsLoginStrategyServiceAccount
|
||||
} else if oauth2.IsIdpEnabled() {
|
||||
loginStrategy = models.LoginDetailsLoginStrategyRedirect
|
||||
// initialize new oauth2 client
|
||||
oauth2Client, err := oauth2.NewOauth2ProviderClient(ctx, nil)
|
||||
@@ -238,7 +247,7 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
|
||||
log.Println("error login:", err)
|
||||
return nil, errorGeneric
|
||||
}
|
||||
credentials := mcsCredentials{minioCredentials: creds}
|
||||
credentials := mcsCredentials{mcsCredentials: creds}
|
||||
jwt, err := login(credentials, actions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -251,3 +260,23 @@ func getLoginOauth2AuthResponse(lr *models.LoginOauth2AuthRequest) (*models.Logi
|
||||
}
|
||||
return nil, errorGeneric
|
||||
}
|
||||
|
||||
// getLoginMkubeResponse validate the provided service account token against mkube
|
||||
func getLoginMkubeResponse(lmr *models.LoginMkubeRequest) (*models.LoginResponse, error) {
|
||||
creds, err := newMcsCredentials("", *lmr.Jwt, "")
|
||||
if err != nil {
|
||||
log.Println("error login:", err)
|
||||
return nil, errInvalidCredentials
|
||||
}
|
||||
credentials := mcsCredentials{mcsCredentials: creds}
|
||||
var actions []string
|
||||
jwt, err := login(credentials, actions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// serialize output
|
||||
loginResponse := &models.LoginResponse{
|
||||
SessionID: *jwt,
|
||||
}
|
||||
return loginResponse, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user