mirror of https://github.com/minio/minio.git
Implement STS account info API (#16115)
This commit is contained in:
parent
939c0100a6
commit
76dde82b41
|
@ -528,6 +528,89 @@ func (a adminAPIHandlers) AddUser(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// TemporaryAccountInfo - GET /minio/admin/v3/temporary-account-info
|
||||
func (a adminAPIHandlers) TemporaryAccountInfo(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := newContext(r, w, "TemporaryAccountInfo")
|
||||
|
||||
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
|
||||
|
||||
// Get current object layer instance.
|
||||
objectAPI := newObjectLayerFn()
|
||||
if objectAPI == nil || globalNotificationSys == nil {
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrServerNotInitialized), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
cred, claims, owner, s3Err := validateAdminSignature(ctx, r, "")
|
||||
if s3Err != ErrNone {
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(s3Err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
accessKey := mux.Vars(r)["accessKey"]
|
||||
if accessKey == "" {
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrInvalidRequest), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if !globalIAMSys.IsAllowed(iampolicy.Args{
|
||||
AccountName: cred.AccessKey,
|
||||
Action: iampolicy.ListTemporaryAccountsAdminAction,
|
||||
ConditionValues: getConditionValues(r, "", cred.AccessKey, claims),
|
||||
IsOwner: owner,
|
||||
Claims: claims,
|
||||
}) {
|
||||
writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
stsAccount, policy, err := globalIAMSys.GetTemporaryAccount(ctx, accessKey)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
var stsAccountPolicy iampolicy.Policy
|
||||
|
||||
if policy != nil {
|
||||
stsAccountPolicy = *policy
|
||||
} else {
|
||||
policiesNames, err := globalIAMSys.PolicyDBGet(stsAccount.ParentUser, false)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
stsAccountPolicy = globalIAMSys.GetCombinedPolicy(policiesNames...)
|
||||
}
|
||||
|
||||
policyJSON, err := json.MarshalIndent(stsAccountPolicy, "", " ")
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
infoResp := madmin.TemporaryAccountInfoResp{
|
||||
ParentUser: stsAccount.ParentUser,
|
||||
AccountStatus: stsAccount.Status,
|
||||
ImpliedPolicy: policy == nil,
|
||||
Policy: string(policyJSON),
|
||||
}
|
||||
|
||||
data, err := json.Marshal(infoResp)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
encryptedData, err := madmin.EncryptData(cred.SecretKey, data)
|
||||
if err != nil {
|
||||
writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
writeSuccessResponseJSON(w, encryptedData)
|
||||
}
|
||||
|
||||
// AddServiceAccount - PUT /minio/admin/v3/add-service-account
|
||||
func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := newContext(r, w, "AddServiceAccount")
|
||||
|
|
|
@ -142,6 +142,9 @@ func registerAdminRouter(router *mux.Router, enableConfigOps bool) {
|
|||
adminRouter.Methods(http.MethodGet).Path(adminVersion + "/list-service-accounts").HandlerFunc(gz(httpTraceHdrs(adminAPI.ListServiceAccounts)))
|
||||
adminRouter.Methods(http.MethodDelete).Path(adminVersion+"/delete-service-account").HandlerFunc(gz(httpTraceHdrs(adminAPI.DeleteServiceAccount))).Queries("accessKey", "{accessKey:.*}")
|
||||
|
||||
// STS accounts ops
|
||||
adminRouter.Methods(http.MethodGet).Path(adminVersion+"/temporary-account-info").HandlerFunc(gz(httpTraceHdrs(adminAPI.TemporaryAccountInfo))).Queries("accessKey", "{accessKey:.*}")
|
||||
|
||||
// Info policy IAM latest
|
||||
adminRouter.Methods(http.MethodGet).Path(adminVersion+"/info-canned-policy").HandlerFunc(gz(httpTraceHdrs(adminAPI.InfoCannedPolicy))).Queries("name", "{name:.*}")
|
||||
// List policies latest
|
||||
|
|
85
cmd/iam.go
85
cmd/iam.go
|
@ -1034,7 +1034,7 @@ func (sys *IAMSys) GetServiceAccount(ctx context.Context, accessKey string) (aut
|
|||
}
|
||||
|
||||
func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (UserIdentity, *iampolicy.Policy, error) {
|
||||
sa, embeddedPolicy, err := sys.getAccountWithEmbeddedPolicy(ctx, accessKey)
|
||||
sa, jwtClaims, err := sys.getAccountWithClaims(ctx, accessKey)
|
||||
if err != nil {
|
||||
if err == errNoSuchAccount {
|
||||
return UserIdentity{}, nil, errNoSuchServiceAccount
|
||||
|
@ -1045,11 +1045,38 @@ func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (Use
|
|||
return UserIdentity{}, nil, errNoSuchServiceAccount
|
||||
}
|
||||
|
||||
var embeddedPolicy *iampolicy.Policy
|
||||
|
||||
pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
|
||||
sp, spok := jwtClaims.Lookup(iampolicy.SessionPolicyName)
|
||||
if ptok && spok && pt == embeddedPolicyType {
|
||||
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
||||
if err != nil {
|
||||
return UserIdentity{}, nil, err
|
||||
}
|
||||
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
||||
if err != nil {
|
||||
return UserIdentity{}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sa, embeddedPolicy, nil
|
||||
}
|
||||
|
||||
// GetTemporaryAccount - wrapper method to get information about a temporary account
|
||||
func (sys *IAMSys) GetTemporaryAccount(ctx context.Context, accessKey string) (auth.Credentials, *iampolicy.Policy, error) {
|
||||
tmpAcc, embeddedPolicy, err := sys.getTempAccount(ctx, accessKey)
|
||||
if err != nil {
|
||||
return auth.Credentials{}, nil, err
|
||||
}
|
||||
// Hide secret & session keys
|
||||
tmpAcc.Credentials.SecretKey = ""
|
||||
tmpAcc.Credentials.SessionToken = ""
|
||||
return tmpAcc.Credentials, embeddedPolicy, nil
|
||||
}
|
||||
|
||||
func (sys *IAMSys) getTempAccount(ctx context.Context, accessKey string) (UserIdentity, *iampolicy.Policy, error) {
|
||||
tmpAcc, embeddedPolicy, err := sys.getAccountWithEmbeddedPolicy(ctx, accessKey)
|
||||
tmpAcc, claims, err := sys.getAccountWithClaims(ctx, accessKey)
|
||||
if err != nil {
|
||||
if err == errNoSuchAccount {
|
||||
return UserIdentity{}, nil, errNoSuchTempAccount
|
||||
|
@ -1060,43 +1087,43 @@ func (sys *IAMSys) getTempAccount(ctx context.Context, accessKey string) (UserId
|
|||
return UserIdentity{}, nil, errNoSuchTempAccount
|
||||
}
|
||||
|
||||
return tmpAcc, embeddedPolicy, nil
|
||||
}
|
||||
|
||||
// getAccountWithEmbeddedPolicy - gets information about an account with its embedded policy if found
|
||||
func (sys *IAMSys) getAccountWithEmbeddedPolicy(ctx context.Context, accessKey string) (u UserIdentity, p *iampolicy.Policy, err error) {
|
||||
if !sys.Initialized() {
|
||||
return u, nil, errServerNotInitialized
|
||||
}
|
||||
|
||||
sa, ok := sys.store.GetUser(accessKey)
|
||||
if !ok {
|
||||
return u, nil, errNoSuchAccount
|
||||
}
|
||||
|
||||
var embeddedPolicy *iampolicy.Policy
|
||||
|
||||
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
|
||||
if err != nil {
|
||||
jwtClaims, err = auth.ExtractClaims(sa.Credentials.SessionToken, globalActiveCred.SecretKey)
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
}
|
||||
}
|
||||
pt, ptok := jwtClaims.Lookup(iamPolicyClaimNameSA())
|
||||
sp, spok := jwtClaims.Lookup(iampolicy.SessionPolicyName)
|
||||
if ptok && spok && pt == embeddedPolicyType {
|
||||
sp, spok := claims.Lookup(iampolicy.SessionPolicyName)
|
||||
if spok {
|
||||
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
return UserIdentity{}, nil, err
|
||||
}
|
||||
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
||||
if err != nil {
|
||||
return u, nil, err
|
||||
return UserIdentity{}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sa, embeddedPolicy, nil
|
||||
return tmpAcc, embeddedPolicy, nil
|
||||
}
|
||||
|
||||
// getAccountWithClaims - gets information about an account with claims
|
||||
func (sys *IAMSys) getAccountWithClaims(ctx context.Context, accessKey string) (UserIdentity, *jwt.MapClaims, error) {
|
||||
if !sys.Initialized() {
|
||||
return UserIdentity{}, nil, errServerNotInitialized
|
||||
}
|
||||
|
||||
acc, ok := sys.store.GetUser(accessKey)
|
||||
if !ok {
|
||||
return UserIdentity{}, nil, errNoSuchAccount
|
||||
}
|
||||
|
||||
jwtClaims, err := auth.ExtractClaims(acc.Credentials.SessionToken, acc.Credentials.SecretKey)
|
||||
if err != nil {
|
||||
jwtClaims, err = auth.ExtractClaims(acc.Credentials.SessionToken, globalActiveCred.SecretKey)
|
||||
if err != nil {
|
||||
return UserIdentity{}, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return acc, jwtClaims, nil
|
||||
}
|
||||
|
||||
// GetClaimsForSvcAcc - gets the claims associated with the service account.
|
||||
|
|
Loading…
Reference in New Issue