mirror of
https://github.com/minio/minio.git
synced 2025-04-20 02:27:50 -04:00
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
|
// AddServiceAccount - PUT /minio/admin/v3/add-service-account
|
||||||
func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Request) {
|
func (a adminAPIHandlers) AddServiceAccount(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContext(r, w, "AddServiceAccount")
|
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.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:.*}")
|
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
|
// Info policy IAM latest
|
||||||
adminRouter.Methods(http.MethodGet).Path(adminVersion+"/info-canned-policy").HandlerFunc(gz(httpTraceHdrs(adminAPI.InfoCannedPolicy))).Queries("name", "{name:.*}")
|
adminRouter.Methods(http.MethodGet).Path(adminVersion+"/info-canned-policy").HandlerFunc(gz(httpTraceHdrs(adminAPI.InfoCannedPolicy))).Queries("name", "{name:.*}")
|
||||||
// List policies latest
|
// 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) {
|
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 != nil {
|
||||||
if err == errNoSuchAccount {
|
if err == errNoSuchAccount {
|
||||||
return UserIdentity{}, nil, errNoSuchServiceAccount
|
return UserIdentity{}, nil, errNoSuchServiceAccount
|
||||||
@ -1045,11 +1045,38 @@ func (sys *IAMSys) getServiceAccount(ctx context.Context, accessKey string) (Use
|
|||||||
return UserIdentity{}, nil, errNoSuchServiceAccount
|
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
|
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) {
|
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 != nil {
|
||||||
if err == errNoSuchAccount {
|
if err == errNoSuchAccount {
|
||||||
return UserIdentity{}, nil, errNoSuchTempAccount
|
return UserIdentity{}, nil, errNoSuchTempAccount
|
||||||
@ -1060,43 +1087,43 @@ func (sys *IAMSys) getTempAccount(ctx context.Context, accessKey string) (UserId
|
|||||||
return UserIdentity{}, nil, errNoSuchTempAccount
|
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
|
var embeddedPolicy *iampolicy.Policy
|
||||||
|
|
||||||
jwtClaims, err := auth.ExtractClaims(sa.Credentials.SessionToken, sa.Credentials.SecretKey)
|
sp, spok := claims.Lookup(iampolicy.SessionPolicyName)
|
||||||
if err != nil {
|
if spok {
|
||||||
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 {
|
|
||||||
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
policyBytes, err := base64.StdEncoding.DecodeString(sp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return u, nil, err
|
return UserIdentity{}, nil, err
|
||||||
}
|
}
|
||||||
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
embeddedPolicy, err = iampolicy.ParseConfig(bytes.NewReader(policyBytes))
|
||||||
if err != nil {
|
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.
|
// GetClaimsForSvcAcc - gets the claims associated with the service account.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user