Implement STS account info API (#16115)

This commit is contained in:
Anis Elleuch 2022-12-13 17:38:50 +01:00 committed by GitHub
parent 939c0100a6
commit 76dde82b41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 142 additions and 29 deletions

View file

@ -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")

View file

@ -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

View file

@ -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.