github.com/minio/console@v1.3.0/api/client-admin.go (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"io"
    24  	"net"
    25  	"net/http"
    26  	"net/url"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/minio/console/pkg"
    31  
    32  	"github.com/minio/console/pkg/utils"
    33  
    34  	"github.com/minio/console/models"
    35  	"github.com/minio/madmin-go/v3"
    36  	"github.com/minio/minio-go/v7/pkg/credentials"
    37  	iampolicy "github.com/minio/pkg/v2/policy"
    38  )
    39  
    40  const globalAppName = "MinIO Console"
    41  
    42  // MinioAdmin interface with all functions to be implemented
    43  // by mock when testing, it should include all MinioAdmin respective api calls
    44  // that are used within this project.
    45  type MinioAdmin interface {
    46  	listUsers(ctx context.Context) (map[string]madmin.UserInfo, error)
    47  	addUser(ctx context.Context, acessKey, SecretKey string) error
    48  	removeUser(ctx context.Context, accessKey string) error
    49  	getUserInfo(ctx context.Context, accessKey string) (madmin.UserInfo, error)
    50  	setUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error
    51  	listGroups(ctx context.Context) ([]string, error)
    52  	updateGroupMembers(ctx context.Context, greq madmin.GroupAddRemove) error
    53  	getGroupDescription(ctx context.Context, group string) (*madmin.GroupDesc, error)
    54  	setGroupStatus(ctx context.Context, group string, status madmin.GroupStatus) error
    55  	listPolicies(ctx context.Context) (map[string]*iampolicy.Policy, error)
    56  	getPolicy(ctx context.Context, name string) (*iampolicy.Policy, error)
    57  	removePolicy(ctx context.Context, name string) error
    58  	addPolicy(ctx context.Context, name string, policy *iampolicy.Policy) error
    59  	setPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error
    60  	getConfigKV(ctx context.Context, key string) ([]byte, error)
    61  	helpConfigKV(ctx context.Context, subSys, key string, envOnly bool) (madmin.Help, error)
    62  	helpConfigKVGlobal(ctx context.Context, envOnly bool) (madmin.Help, error)
    63  	setConfigKV(ctx context.Context, kv string) (restart bool, err error)
    64  	delConfigKV(ctx context.Context, kv string) (err error)
    65  	serviceRestart(ctx context.Context) error
    66  	serverInfo(ctx context.Context) (madmin.InfoMessage, error)
    67  	startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error)
    68  	stopProfiling(ctx context.Context) (io.ReadCloser, error)
    69  	serviceTrace(ctx context.Context, threshold int64, s3, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo
    70  	getLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo
    71  	AccountInfo(ctx context.Context) (madmin.AccountInfo, error)
    72  	heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
    73  		forceStart, forceStop bool) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error)
    74  	// Service Accounts
    75  	addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error)
    76  	listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error)
    77  	deleteServiceAccount(ctx context.Context, serviceAccount string) error
    78  	infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error)
    79  	updateServiceAccount(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error
    80  	// Remote Buckets
    81  	listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error)
    82  	getRemoteBucket(ctx context.Context, bucket, arnType string) (targets *madmin.BucketTarget, err error)
    83  	removeRemoteBucket(ctx context.Context, bucket, arn string) error
    84  	addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error)
    85  	// Account password management
    86  	changePassword(ctx context.Context, accessKey, secretKey string) error
    87  	serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error)
    88  	// List Tiers
    89  	listTiers(ctx context.Context) ([]*madmin.TierConfig, error)
    90  	// Tier Info
    91  	tierStats(ctx context.Context) ([]madmin.TierInfo, error)
    92  	// Add Tier
    93  	addTier(ctx context.Context, tier *madmin.TierConfig) error
    94  	// Edit Tier Credentials
    95  	editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error
    96  	// verify Tier status
    97  	verifyTierStatus(ctx context.Context, tierName string) error
    98  	// Speedtest
    99  	speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error)
   100  	// Site Relication
   101  	getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error)
   102  	addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error)
   103  	editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error)
   104  	deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error)
   105  
   106  	// Replication status
   107  	getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error)
   108  
   109  	// KMS
   110  	kmsStatus(ctx context.Context) (madmin.KMSStatus, error)
   111  	kmsMetrics(ctx context.Context) (*madmin.KMSMetrics, error)
   112  	kmsAPIs(ctx context.Context) ([]madmin.KMSAPI, error)
   113  	kmsVersion(ctx context.Context) (*madmin.KMSVersion, error)
   114  	createKey(ctx context.Context, key string) error
   115  	importKey(ctx context.Context, key string, content []byte) error
   116  	listKeys(ctx context.Context, pattern string) ([]madmin.KMSKeyInfo, error)
   117  	keyStatus(ctx context.Context, key string) (*madmin.KMSKeyStatus, error)
   118  	deleteKey(ctx context.Context, key string) error
   119  	setKMSPolicy(ctx context.Context, policy string, content []byte) error
   120  	assignPolicy(ctx context.Context, policy string, content []byte) error
   121  	describePolicy(ctx context.Context, policy string) (*madmin.KMSDescribePolicy, error)
   122  	getKMSPolicy(ctx context.Context, policy string) (*madmin.KMSPolicy, error)
   123  	listKMSPolicies(ctx context.Context, pattern string) ([]madmin.KMSPolicyInfo, error)
   124  	deletePolicy(ctx context.Context, policy string) error
   125  	describeIdentity(ctx context.Context, identity string) (*madmin.KMSDescribeIdentity, error)
   126  	describeSelfIdentity(ctx context.Context) (*madmin.KMSDescribeSelfIdentity, error)
   127  	deleteIdentity(ctx context.Context, identity string) error
   128  	listIdentities(ctx context.Context, pattern string) ([]madmin.KMSIdentityInfo, error)
   129  
   130  	// IDP
   131  	addOrUpdateIDPConfig(ctx context.Context, idpType, cfgName, cfgData string, update bool) (restart bool, err error)
   132  	listIDPConfig(ctx context.Context, idpType string) ([]madmin.IDPListItem, error)
   133  	deleteIDPConfig(ctx context.Context, idpType, cfgName string) (restart bool, err error)
   134  	getIDPConfig(ctx context.Context, cfgType, cfgName string) (c madmin.IDPConfig, err error)
   135  
   136  	// LDAP
   137  	getLDAPPolicyEntities(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error)
   138  }
   139  
   140  // Interface implementation
   141  //
   142  // Define the structure of a minIO Client and define the functions that are actually used
   143  // from minIO api.
   144  type AdminClient struct {
   145  	Client *madmin.AdminClient
   146  }
   147  
   148  func (ac AdminClient) changePassword(ctx context.Context, accessKey, secretKey string) error {
   149  	return ac.Client.SetUser(ctx, accessKey, secretKey, madmin.AccountEnabled)
   150  }
   151  
   152  // implements madmin.ListUsers()
   153  func (ac AdminClient) listUsers(ctx context.Context) (map[string]madmin.UserInfo, error) {
   154  	return ac.Client.ListUsers(ctx)
   155  }
   156  
   157  // implements madmin.AddUser()
   158  func (ac AdminClient) addUser(ctx context.Context, accessKey, secretKey string) error {
   159  	return ac.Client.AddUser(ctx, accessKey, secretKey)
   160  }
   161  
   162  // implements madmin.RemoveUser()
   163  func (ac AdminClient) removeUser(ctx context.Context, accessKey string) error {
   164  	return ac.Client.RemoveUser(ctx, accessKey)
   165  }
   166  
   167  // implements madmin.GetUserInfo()
   168  func (ac AdminClient) getUserInfo(ctx context.Context, accessKey string) (madmin.UserInfo, error) {
   169  	return ac.Client.GetUserInfo(ctx, accessKey)
   170  }
   171  
   172  // implements madmin.SetUserStatus()
   173  func (ac AdminClient) setUserStatus(ctx context.Context, accessKey string, status madmin.AccountStatus) error {
   174  	return ac.Client.SetUserStatus(ctx, accessKey, status)
   175  }
   176  
   177  // implements madmin.ListGroups()
   178  func (ac AdminClient) listGroups(ctx context.Context) ([]string, error) {
   179  	return ac.Client.ListGroups(ctx)
   180  }
   181  
   182  // implements madmin.UpdateGroupMembers()
   183  func (ac AdminClient) updateGroupMembers(ctx context.Context, greq madmin.GroupAddRemove) error {
   184  	return ac.Client.UpdateGroupMembers(ctx, greq)
   185  }
   186  
   187  // implements madmin.GetGroupDescription(group)
   188  func (ac AdminClient) getGroupDescription(ctx context.Context, group string) (*madmin.GroupDesc, error) {
   189  	return ac.Client.GetGroupDescription(ctx, group)
   190  }
   191  
   192  // implements madmin.SetGroupStatus(group, status)
   193  func (ac AdminClient) setGroupStatus(ctx context.Context, group string, status madmin.GroupStatus) error {
   194  	return ac.Client.SetGroupStatus(ctx, group, status)
   195  }
   196  
   197  // implements madmin.ListCannedPolicies()
   198  func (ac AdminClient) listPolicies(ctx context.Context) (map[string]*iampolicy.Policy, error) {
   199  	policyMap, err := ac.Client.ListCannedPolicies(ctx)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	policies := make(map[string]*iampolicy.Policy, len(policyMap))
   204  	for k, v := range policyMap {
   205  		p, err := iampolicy.ParseConfig(bytes.NewReader(v))
   206  		if err != nil {
   207  			return nil, err
   208  		}
   209  		policies[k] = p
   210  	}
   211  	return policies, nil
   212  }
   213  
   214  // implements madmin.ListCannedPolicies()
   215  func (ac AdminClient) getPolicy(ctx context.Context, name string) (*iampolicy.Policy, error) {
   216  	praw, err := ac.Client.InfoCannedPolicy(ctx, name)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	return iampolicy.ParseConfig(bytes.NewReader(praw))
   221  }
   222  
   223  // implements madmin.RemoveCannedPolicy()
   224  func (ac AdminClient) removePolicy(ctx context.Context, name string) error {
   225  	return ac.Client.RemoveCannedPolicy(ctx, name)
   226  }
   227  
   228  // implements madmin.AddCannedPolicy()
   229  func (ac AdminClient) addPolicy(ctx context.Context, name string, policy *iampolicy.Policy) error {
   230  	buf, err := json.Marshal(policy)
   231  	if err != nil {
   232  		return err
   233  	}
   234  	return ac.Client.AddCannedPolicy(ctx, name, buf)
   235  }
   236  
   237  // implements madmin.SetPolicy()
   238  func (ac AdminClient) setPolicy(ctx context.Context, policyName, entityName string, isGroup bool) error {
   239  	return ac.Client.SetPolicy(ctx, policyName, entityName, isGroup)
   240  }
   241  
   242  // implements madmin.GetConfigKV()
   243  func (ac AdminClient) getConfigKV(ctx context.Context, key string) ([]byte, error) {
   244  	return ac.Client.GetConfigKV(ctx, key)
   245  }
   246  
   247  // implements madmin.HelpConfigKV()
   248  func (ac AdminClient) helpConfigKV(ctx context.Context, subSys, key string, envOnly bool) (madmin.Help, error) {
   249  	return ac.Client.HelpConfigKV(ctx, subSys, key, envOnly)
   250  }
   251  
   252  // implements madmin.helpConfigKVGlobal()
   253  func (ac AdminClient) helpConfigKVGlobal(ctx context.Context, envOnly bool) (madmin.Help, error) {
   254  	return ac.Client.HelpConfigKV(ctx, "", "", envOnly)
   255  }
   256  
   257  // implements madmin.SetConfigKV()
   258  func (ac AdminClient) setConfigKV(ctx context.Context, kv string) (restart bool, err error) {
   259  	return ac.Client.SetConfigKV(ctx, kv)
   260  }
   261  
   262  // implements madmin.DelConfigKV()
   263  func (ac AdminClient) delConfigKV(ctx context.Context, kv string) (err error) {
   264  	_, err = ac.Client.DelConfigKV(ctx, kv)
   265  	return err
   266  }
   267  
   268  // implements madmin.ServiceRestart()
   269  func (ac AdminClient) serviceRestart(ctx context.Context) (err error) {
   270  	return ac.Client.ServiceRestart(ctx)
   271  }
   272  
   273  // implements madmin.ServerInfo()
   274  func (ac AdminClient) serverInfo(ctx context.Context) (madmin.InfoMessage, error) {
   275  	return ac.Client.ServerInfo(ctx)
   276  }
   277  
   278  // implements madmin.StartProfiling()
   279  func (ac AdminClient) startProfiling(ctx context.Context, profiler madmin.ProfilerType) ([]madmin.StartProfilingResult, error) {
   280  	return ac.Client.StartProfiling(ctx, profiler)
   281  }
   282  
   283  // implements madmin.DownloadProfilingData()
   284  func (ac AdminClient) stopProfiling(ctx context.Context) (io.ReadCloser, error) {
   285  	return ac.Client.DownloadProfilingData(ctx)
   286  }
   287  
   288  // implements madmin.ServiceTrace()
   289  func (ac AdminClient) serviceTrace(ctx context.Context, threshold int64, _, internal, storage, os, errTrace bool) <-chan madmin.ServiceTraceInfo {
   290  	thresholdT := time.Duration(threshold)
   291  
   292  	tracingOptions := madmin.ServiceTraceOpts{
   293  		S3:         true,
   294  		OnlyErrors: errTrace,
   295  		Internal:   internal,
   296  		Storage:    storage,
   297  		OS:         os,
   298  		Threshold:  thresholdT,
   299  	}
   300  
   301  	return ac.Client.ServiceTrace(ctx, tracingOptions)
   302  }
   303  
   304  // implements madmin.GetLogs()
   305  func (ac AdminClient) getLogs(ctx context.Context, node string, lineCnt int, logKind string) <-chan madmin.LogInfo {
   306  	return ac.Client.GetLogs(ctx, node, lineCnt, logKind)
   307  }
   308  
   309  // implements madmin.AddServiceAccount()
   310  func (ac AdminClient) addServiceAccount(ctx context.Context, policy string, user string, accessKey string, secretKey string, name string, description string, expiry *time.Time, comment string) (madmin.Credentials, error) {
   311  	return ac.Client.AddServiceAccount(ctx, madmin.AddServiceAccountReq{
   312  		Policy:      []byte(policy),
   313  		TargetUser:  user,
   314  		AccessKey:   accessKey,
   315  		SecretKey:   secretKey,
   316  		Name:        name,
   317  		Description: description,
   318  		Expiration:  expiry,
   319  		Comment:     comment,
   320  	})
   321  }
   322  
   323  // implements madmin.ListServiceAccounts()
   324  func (ac AdminClient) listServiceAccounts(ctx context.Context, user string) (madmin.ListServiceAccountsResp, error) {
   325  	return ac.Client.ListServiceAccounts(ctx, user)
   326  }
   327  
   328  // implements madmin.DeleteServiceAccount()
   329  func (ac AdminClient) deleteServiceAccount(ctx context.Context, serviceAccount string) error {
   330  	return ac.Client.DeleteServiceAccount(ctx, serviceAccount)
   331  }
   332  
   333  // implements madmin.InfoServiceAccount()
   334  func (ac AdminClient) infoServiceAccount(ctx context.Context, serviceAccount string) (madmin.InfoServiceAccountResp, error) {
   335  	return ac.Client.InfoServiceAccount(ctx, serviceAccount)
   336  }
   337  
   338  // implements madmin.UpdateServiceAccount()
   339  func (ac AdminClient) updateServiceAccount(ctx context.Context, serviceAccount string, opts madmin.UpdateServiceAccountReq) error {
   340  	return ac.Client.UpdateServiceAccount(ctx, serviceAccount, opts)
   341  }
   342  
   343  // AccountInfo implements madmin.AccountInfo()
   344  func (ac AdminClient) AccountInfo(ctx context.Context) (madmin.AccountInfo, error) {
   345  	return ac.Client.AccountInfo(ctx, madmin.AccountOpts{})
   346  }
   347  
   348  func (ac AdminClient) heal(ctx context.Context, bucket, prefix string, healOpts madmin.HealOpts, clientToken string,
   349  	forceStart, forceStop bool,
   350  ) (healStart madmin.HealStartSuccess, healTaskStatus madmin.HealTaskStatus, err error) {
   351  	return ac.Client.Heal(ctx, bucket, prefix, healOpts, clientToken, forceStart, forceStop)
   352  }
   353  
   354  // listRemoteBuckets - return a list of remote buckets
   355  func (ac AdminClient) listRemoteBuckets(ctx context.Context, bucket, arnType string) (targets []madmin.BucketTarget, err error) {
   356  	return ac.Client.ListRemoteTargets(ctx, bucket, arnType)
   357  }
   358  
   359  // getRemoteBucket - gets remote bucked based on a given bucket name
   360  func (ac AdminClient) getRemoteBucket(ctx context.Context, bucket, arnType string) (*madmin.BucketTarget, error) {
   361  	targets, err := ac.Client.ListRemoteTargets(ctx, bucket, arnType)
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  	if len(targets) > 0 {
   366  		return &targets[0], nil
   367  	}
   368  	return nil, err
   369  }
   370  
   371  // removeRemoteBucket removes a remote target associated with particular ARN for this bucket
   372  func (ac AdminClient) removeRemoteBucket(ctx context.Context, bucket, arn string) error {
   373  	return ac.Client.RemoveRemoteTarget(ctx, bucket, arn)
   374  }
   375  
   376  // addRemoteBucket sets up a remote target for this bucket
   377  func (ac AdminClient) addRemoteBucket(ctx context.Context, bucket string, target *madmin.BucketTarget) (string, error) {
   378  	return ac.Client.SetRemoteTarget(ctx, bucket, target)
   379  }
   380  
   381  func (ac AdminClient) setBucketQuota(ctx context.Context, bucket string, quota *madmin.BucketQuota) error {
   382  	return ac.Client.SetBucketQuota(ctx, bucket, quota)
   383  }
   384  
   385  func (ac AdminClient) getBucketQuota(ctx context.Context, bucket string) (madmin.BucketQuota, error) {
   386  	return ac.Client.GetBucketQuota(ctx, bucket)
   387  }
   388  
   389  // serverHealthInfo implements mc.ServerHealthInfo - Connect to a minio server and call Health Info Management API
   390  func (ac AdminClient) serverHealthInfo(ctx context.Context, healthDataTypes []madmin.HealthDataType, deadline time.Duration) (interface{}, string, error) {
   391  	info := madmin.HealthInfo{}
   392  	var healthInfo interface{}
   393  	var version string
   394  	var tryCount int
   395  	for info.Version == "" && tryCount < 10 {
   396  		resp, version, err := ac.Client.ServerHealthInfo(ctx, healthDataTypes, deadline, "")
   397  		if err != nil {
   398  			return nil, version, err
   399  		}
   400  		decoder := json.NewDecoder(resp.Body)
   401  		for {
   402  			if err = decoder.Decode(&info); err != nil {
   403  				break
   404  			}
   405  		}
   406  		tryCount++
   407  		time.Sleep(2 * time.Second)
   408  
   409  	}
   410  	if info.Version == "" {
   411  		return nil, "", ErrHealthReportFail
   412  	}
   413  	healthInfo = info
   414  
   415  	return healthInfo, version, nil
   416  }
   417  
   418  // implements madmin.listTiers()
   419  func (ac AdminClient) listTiers(ctx context.Context) ([]*madmin.TierConfig, error) {
   420  	return ac.Client.ListTiers(ctx)
   421  }
   422  
   423  // implements madmin.tierStats()
   424  func (ac AdminClient) tierStats(ctx context.Context) ([]madmin.TierInfo, error) {
   425  	return ac.Client.TierStats(ctx)
   426  }
   427  
   428  // implements madmin.AddTier()
   429  func (ac AdminClient) addTier(ctx context.Context, cfg *madmin.TierConfig) error {
   430  	return ac.Client.AddTier(ctx, cfg)
   431  }
   432  
   433  // implements madmin.Inspect()
   434  func (ac AdminClient) inspect(ctx context.Context, insOpts madmin.InspectOptions) ([]byte, io.ReadCloser, error) {
   435  	return ac.Client.Inspect(ctx, insOpts)
   436  }
   437  
   438  // implements madmin.EditTier()
   439  func (ac AdminClient) editTierCreds(ctx context.Context, tierName string, creds madmin.TierCreds) error {
   440  	return ac.Client.EditTier(ctx, tierName, creds)
   441  }
   442  
   443  // implements madmin.VerifyTier()
   444  func (ac AdminClient) verifyTierStatus(ctx context.Context, tierName string) error {
   445  	return ac.Client.VerifyTier(ctx, tierName)
   446  }
   447  
   448  func NewMinioAdminClient(ctx context.Context, sessionClaims *models.Principal) (*madmin.AdminClient, error) {
   449  	clientIP := utils.ClientIPFromContext(ctx)
   450  	adminClient, err := newAdminFromClaims(sessionClaims, clientIP)
   451  	if err != nil {
   452  		return nil, err
   453  	}
   454  	adminClient.SetAppInfo(globalAppName, pkg.Version)
   455  	return adminClient, nil
   456  }
   457  
   458  // newAdminFromClaims creates a minio admin from Decrypted claims using Assume role credentials
   459  func newAdminFromClaims(claims *models.Principal, clientIP string) (*madmin.AdminClient, error) {
   460  	tlsEnabled := getMinIOEndpointIsSecure()
   461  	endpoint := getMinIOEndpoint()
   462  
   463  	adminClient, err := madmin.NewWithOptions(endpoint, &madmin.Options{
   464  		Creds:  credentials.NewStaticV4(claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken),
   465  		Secure: tlsEnabled,
   466  	})
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  	adminClient.SetAppInfo(globalAppName, pkg.Version)
   471  	adminClient.SetCustomTransport(GetConsoleHTTPClient(getMinIOServer(), clientIP).Transport)
   472  	return adminClient, nil
   473  }
   474  
   475  // newAdminFromCreds Creates a minio client using custom credentials for connecting to a remote host
   476  func newAdminFromCreds(accessKey, secretKey, endpoint string, tlsEnabled bool) (*madmin.AdminClient, error) {
   477  	minioClient, err := madmin.NewWithOptions(endpoint, &madmin.Options{
   478  		Creds:  credentials.NewStaticV4(accessKey, secretKey, ""),
   479  		Secure: tlsEnabled,
   480  	})
   481  	if err != nil {
   482  		return nil, err
   483  	}
   484  	minioClient.SetAppInfo(globalAppName, pkg.Version)
   485  	return minioClient, nil
   486  }
   487  
   488  // isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
   489  // that points to the local machine - FQDN are not supported
   490  func isLocalIPEndpoint(addr string) bool {
   491  	u, err := url.Parse(addr)
   492  	if err != nil {
   493  		return false
   494  	}
   495  	return isLocalIPAddress(u.Hostname())
   496  }
   497  
   498  // isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
   499  // that points to the local machine - FQDN are not supported
   500  func isLocalIPAddress(ipAddr string) bool {
   501  	if ipAddr == "" {
   502  		return false
   503  	}
   504  	ip := net.ParseIP(ipAddr)
   505  	return ip != nil && ip.IsLoopback()
   506  }
   507  
   508  // GetConsoleHTTPClient caches different http clients depending on the target endpoint while taking
   509  // in consideration CA certs stored in ${HOME}/.console/certs/CAs and ${HOME}/.minio/certs/CAs
   510  // If the target endpoint points to a loopback device, skip the TLS verification.
   511  func GetConsoleHTTPClient(address string, clientIP string) *http.Client {
   512  	u, err := url.Parse(address)
   513  	if err == nil {
   514  		address = u.Hostname()
   515  	}
   516  
   517  	client := PrepareConsoleHTTPClient(isLocalIPAddress(address), clientIP)
   518  
   519  	return client
   520  }
   521  
   522  func getClientIP(r *http.Request) string {
   523  	// Try to get the IP address from the X-Real-IP header
   524  	// If the X-Real-IP header is not present, then it will return an empty string
   525  	xRealIP := r.Header.Get("X-Real-IP")
   526  	if xRealIP != "" {
   527  		return xRealIP
   528  	}
   529  
   530  	// Try to get the IP address from the X-Forwarded-For header
   531  	// If the X-Forwarded-For header is not present, then it will return an empty string
   532  	xForwardedFor := r.Header.Get("X-Forwarded-For")
   533  	if xForwardedFor != "" {
   534  		// X-Forwarded-For can contain multiple addresses, we return the first one
   535  		split := strings.Split(xForwardedFor, ",")
   536  		if len(split) > 0 {
   537  			return strings.TrimSpace(split[0])
   538  		}
   539  	}
   540  
   541  	// If neither header is present (or they were empty), then fall back to the connection's remote address
   542  	ip, _, err := net.SplitHostPort(r.RemoteAddr)
   543  	if err != nil {
   544  		// In case there's an error, return an empty string
   545  		return ""
   546  	}
   547  	return ip
   548  }
   549  
   550  func (ac AdminClient) speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error) {
   551  	return ac.Client.Speedtest(ctx, opts)
   552  }
   553  
   554  // Site Replication
   555  func (ac AdminClient) getSiteReplicationInfo(ctx context.Context) (*madmin.SiteReplicationInfo, error) {
   556  	res, err := ac.Client.SiteReplicationInfo(ctx)
   557  	if err != nil {
   558  		return nil, err
   559  	}
   560  	return &madmin.SiteReplicationInfo{
   561  		Enabled:                 res.Enabled,
   562  		Name:                    res.Name,
   563  		Sites:                   res.Sites,
   564  		ServiceAccountAccessKey: res.ServiceAccountAccessKey,
   565  	}, nil
   566  }
   567  
   568  func (ac AdminClient) addSiteReplicationInfo(ctx context.Context, sites []madmin.PeerSite, opts madmin.SRAddOptions) (*madmin.ReplicateAddStatus, error) {
   569  	res, err := ac.Client.SiteReplicationAdd(ctx, sites, opts)
   570  	if err != nil {
   571  		return nil, err
   572  	}
   573  
   574  	return &madmin.ReplicateAddStatus{
   575  		Success:                 res.Success,
   576  		Status:                  res.Status,
   577  		ErrDetail:               res.ErrDetail,
   578  		InitialSyncErrorMessage: res.InitialSyncErrorMessage,
   579  	}, nil
   580  }
   581  
   582  func (ac AdminClient) editSiteReplicationInfo(ctx context.Context, site madmin.PeerInfo, opts madmin.SREditOptions) (*madmin.ReplicateEditStatus, error) {
   583  	res, err := ac.Client.SiteReplicationEdit(ctx, site, opts)
   584  	if err != nil {
   585  		return nil, err
   586  	}
   587  	return &madmin.ReplicateEditStatus{
   588  		Success:   res.Success,
   589  		Status:    res.Status,
   590  		ErrDetail: res.ErrDetail,
   591  	}, nil
   592  }
   593  
   594  func (ac AdminClient) deleteSiteReplicationInfo(ctx context.Context, removeReq madmin.SRRemoveReq) (*madmin.ReplicateRemoveStatus, error) {
   595  	res, err := ac.Client.SiteReplicationRemove(ctx, removeReq)
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  	return &madmin.ReplicateRemoveStatus{
   600  		Status:    res.Status,
   601  		ErrDetail: res.ErrDetail,
   602  	}, nil
   603  }
   604  
   605  func (ac AdminClient) getSiteReplicationStatus(ctx context.Context, params madmin.SRStatusOptions) (*madmin.SRStatusInfo, error) {
   606  	res, err := ac.Client.SRStatusInfo(ctx, params)
   607  	if err != nil {
   608  		return nil, err
   609  	}
   610  	return &res, nil
   611  }
   612  
   613  func (ac AdminClient) kmsStatus(ctx context.Context) (madmin.KMSStatus, error) {
   614  	return ac.Client.KMSStatus(ctx)
   615  }
   616  
   617  func (ac AdminClient) kmsMetrics(ctx context.Context) (*madmin.KMSMetrics, error) {
   618  	return ac.Client.KMSMetrics(ctx)
   619  }
   620  
   621  func (ac AdminClient) kmsAPIs(ctx context.Context) ([]madmin.KMSAPI, error) {
   622  	return ac.Client.KMSAPIs(ctx)
   623  }
   624  
   625  func (ac AdminClient) kmsVersion(ctx context.Context) (*madmin.KMSVersion, error) {
   626  	return ac.Client.KMSVersion(ctx)
   627  }
   628  
   629  func (ac AdminClient) createKey(ctx context.Context, key string) error {
   630  	return ac.Client.CreateKey(ctx, key)
   631  }
   632  
   633  func (ac AdminClient) importKey(ctx context.Context, key string, content []byte) error {
   634  	return ac.Client.ImportKey(ctx, key, content)
   635  }
   636  
   637  func (ac AdminClient) listKeys(ctx context.Context, pattern string) ([]madmin.KMSKeyInfo, error) {
   638  	return ac.Client.ListKeys(ctx, pattern)
   639  }
   640  
   641  func (ac AdminClient) keyStatus(ctx context.Context, key string) (*madmin.KMSKeyStatus, error) {
   642  	return ac.Client.GetKeyStatus(ctx, key)
   643  }
   644  
   645  func (ac AdminClient) deleteKey(ctx context.Context, key string) error {
   646  	return ac.Client.DeleteKey(ctx, key)
   647  }
   648  
   649  func (ac AdminClient) setKMSPolicy(ctx context.Context, policy string, content []byte) error {
   650  	return ac.Client.SetKMSPolicy(ctx, policy, content)
   651  }
   652  
   653  func (ac AdminClient) assignPolicy(ctx context.Context, policy string, content []byte) error {
   654  	return ac.Client.AssignPolicy(ctx, policy, content)
   655  }
   656  
   657  func (ac AdminClient) describePolicy(ctx context.Context, policy string) (*madmin.KMSDescribePolicy, error) {
   658  	return ac.Client.DescribePolicy(ctx, policy)
   659  }
   660  
   661  func (ac AdminClient) getKMSPolicy(ctx context.Context, policy string) (*madmin.KMSPolicy, error) {
   662  	return ac.Client.GetPolicy(ctx, policy)
   663  }
   664  
   665  func (ac AdminClient) listKMSPolicies(ctx context.Context, pattern string) ([]madmin.KMSPolicyInfo, error) {
   666  	return ac.Client.ListPolicies(ctx, pattern)
   667  }
   668  
   669  func (ac AdminClient) deletePolicy(ctx context.Context, policy string) error {
   670  	return ac.Client.DeletePolicy(ctx, policy)
   671  }
   672  
   673  func (ac AdminClient) describeIdentity(ctx context.Context, identity string) (*madmin.KMSDescribeIdentity, error) {
   674  	return ac.Client.DescribeIdentity(ctx, identity)
   675  }
   676  
   677  func (ac AdminClient) describeSelfIdentity(ctx context.Context) (*madmin.KMSDescribeSelfIdentity, error) {
   678  	return ac.Client.DescribeSelfIdentity(ctx)
   679  }
   680  
   681  func (ac AdminClient) deleteIdentity(ctx context.Context, identity string) error {
   682  	return ac.Client.DeleteIdentity(ctx, identity)
   683  }
   684  
   685  func (ac AdminClient) listIdentities(ctx context.Context, pattern string) ([]madmin.KMSIdentityInfo, error) {
   686  	return ac.Client.ListIdentities(ctx, pattern)
   687  }
   688  
   689  func (ac AdminClient) addOrUpdateIDPConfig(ctx context.Context, idpType, cfgName, cfgData string, update bool) (restart bool, err error) {
   690  	return ac.Client.AddOrUpdateIDPConfig(ctx, idpType, cfgName, cfgData, update)
   691  }
   692  
   693  func (ac AdminClient) listIDPConfig(ctx context.Context, idpType string) ([]madmin.IDPListItem, error) {
   694  	return ac.Client.ListIDPConfig(ctx, idpType)
   695  }
   696  
   697  func (ac AdminClient) deleteIDPConfig(ctx context.Context, idpType, cfgName string) (restart bool, err error) {
   698  	return ac.Client.DeleteIDPConfig(ctx, idpType, cfgName)
   699  }
   700  
   701  func (ac AdminClient) getIDPConfig(ctx context.Context, idpType, cfgName string) (c madmin.IDPConfig, err error) {
   702  	return ac.Client.GetIDPConfig(ctx, idpType, cfgName)
   703  }
   704  
   705  func (ac AdminClient) getLDAPPolicyEntities(ctx context.Context, query madmin.PolicyEntitiesQuery) (madmin.PolicyEntitiesResult, error) {
   706  	return ac.Client.GetLDAPPolicyEntities(ctx, query)
   707  }