github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/config/config.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/mitchellh/go-homedir"
    12  	"github.com/mitchellh/mapstructure"
    13  	"github.com/spf13/viper"
    14  	apiparams "github.com/treeverse/lakefs/pkg/api/params"
    15  	blockparams "github.com/treeverse/lakefs/pkg/block/params"
    16  	"github.com/treeverse/lakefs/pkg/logging"
    17  )
    18  
    19  var (
    20  	ErrBadConfiguration    = errors.New("bad configuration")
    21  	ErrBadDomainNames      = fmt.Errorf("%w: domain names are prefixes", ErrBadConfiguration)
    22  	ErrMissingRequiredKeys = fmt.Errorf("%w: missing required keys", ErrBadConfiguration)
    23  )
    24  
    25  // UseLocalConfiguration set to true will add defaults that enable a lakeFS run
    26  // without any other configuration like DB or blockstore.
    27  const (
    28  	UseLocalConfiguration   = "local-settings"
    29  	QuickstartConfiguration = "quickstart"
    30  )
    31  
    32  type OIDC struct {
    33  	// configure how users are handled on the lakeFS side:
    34  	ValidateIDTokenClaims  map[string]string `mapstructure:"validate_id_token_claims"`
    35  	DefaultInitialGroups   []string          `mapstructure:"default_initial_groups"`
    36  	InitialGroupsClaimName string            `mapstructure:"initial_groups_claim_name"`
    37  	FriendlyNameClaimName  string            `mapstructure:"friendly_name_claim_name"`
    38  	PersistFriendlyName    bool              `mapstructure:"persist_friendly_name"`
    39  }
    40  
    41  // CookieAuthVerification is related to auth based on a cookie set by an external service
    42  // TODO(isan) consolidate with OIDC
    43  type CookieAuthVerification struct {
    44  	// ValidateIDTokenClaims if set will validate the values (e.g., department: "R&D") exist in the token claims
    45  	ValidateIDTokenClaims map[string]string `mapstructure:"validate_id_token_claims"`
    46  	// DefaultInitialGroups is a list of groups to add to the user on the lakeFS side
    47  	DefaultInitialGroups []string `mapstructure:"default_initial_groups"`
    48  	// InitialGroupsClaimName comma separated list of groups to add to the user on the lakeFS side
    49  	InitialGroupsClaimName string `mapstructure:"initial_groups_claim_name"`
    50  	// FriendlyNameClaimName is the claim name to use as the user's friendly name in places like the UI
    51  	FriendlyNameClaimName string `mapstructure:"friendly_name_claim_name"`
    52  	// ExternalUserIDClaimName is the claim name to use as the user identifier with an IDP
    53  	ExternalUserIDClaimName string `mapstructure:"external_user_id_claim_name"`
    54  	// AuthSource tag each user with label of the IDP
    55  	AuthSource string `mapstructure:"auth_source"`
    56  	// PersistFriendlyName should we persist the friendly name in the KV store
    57  	PersistFriendlyName bool `mapstructure:"persist_friendly_name"`
    58  }
    59  
    60  // S3AuthInfo holds S3-style authentication.
    61  type S3AuthInfo struct {
    62  	CredentialsFile string `mapstructure:"credentials_file"`
    63  	Profile         string
    64  	Credentials     *struct {
    65  		AccessKeyID     SecureString `mapstructure:"access_key_id"`
    66  		SecretAccessKey SecureString `mapstructure:"secret_access_key"`
    67  		SessionToken    SecureString `mapstructure:"session_token"`
    68  	}
    69  }
    70  
    71  // Config - Output struct of configuration, used to validate.  If you read a key using a viper accessor
    72  // rather than accessing a field of this struct, that key will *not* be validated.  So don't
    73  // do that.
    74  type Config struct {
    75  	ListenAddress string `mapstructure:"listen_address"`
    76  	TLS           struct {
    77  		Enabled  bool   `mapstructure:"enabled"`
    78  		CertFile string `mapstructure:"cert_file"`
    79  		KeyFile  string `mapstructure:"key_file"`
    80  	} `mapstructure:"tls"`
    81  
    82  	Actions struct {
    83  		// ActionsEnabled set to false will block any hook execution
    84  		Enabled bool `mapstructure:"enabled"`
    85  		Lua     struct {
    86  			NetHTTPEnabled bool `mapstructure:"net_http_enabled"`
    87  		} `mapstructure:"lua"`
    88  		Env struct {
    89  			Enabled bool   `mapstructure:"enabled"`
    90  			Prefix  string `mapstructure:"prefix"`
    91  		} `mapstructure:"env"`
    92  	} `mapstructure:"actions"`
    93  
    94  	Logging struct {
    95  		Format        string   `mapstructure:"format"`
    96  		Level         string   `mapstructure:"level"`
    97  		Output        []string `mapstructure:"output"`
    98  		FileMaxSizeMB int      `mapstructure:"file_max_size_mb"`
    99  		FilesKeep     int      `mapstructure:"files_keep"`
   100  		AuditLogLevel string   `mapstructure:"audit_log_level"`
   101  		// TraceRequestHeaders work only on 'trace' level, default is false as it may log sensitive data to the log
   102  		TraceRequestHeaders bool `mapstructure:"trace_request_headers"`
   103  	}
   104  
   105  	Database struct {
   106  		// DropTables Development flag to delete tables after successful migration to KV
   107  		DropTables bool `mapstructure:"drop_tables"`
   108  		// Type Name of the KV Store driver DB implementation which is available according to the kv package Drivers function
   109  		Type string `mapstructure:"type" validate:"required"`
   110  
   111  		Local *struct {
   112  			// Path - Local directory path to store the DB files
   113  			Path string `mapstructure:"path"`
   114  			// SyncWrites - Sync ensures data written to disk on each write instead of mem cache
   115  			SyncWrites bool `mapstructure:"sync_writes"`
   116  			// PrefetchSize - Number of elements to prefetch while iterating
   117  			PrefetchSize int `mapstructure:"prefetch_size"`
   118  			// EnableLogging - Enable store and badger (trace only) logging
   119  			EnableLogging bool `mapstructure:"enable_logging"`
   120  		} `mapstructure:"local"`
   121  
   122  		Postgres *struct {
   123  			ConnectionString      SecureString  `mapstructure:"connection_string"`
   124  			MaxOpenConnections    int32         `mapstructure:"max_open_connections"`
   125  			MaxIdleConnections    int32         `mapstructure:"max_idle_connections"`
   126  			ConnectionMaxLifetime time.Duration `mapstructure:"connection_max_lifetime"`
   127  			ScanPageSize          int           `mapstructure:"scan_page_size"`
   128  			Metrics               bool          `mapstructure:"metrics"`
   129  		}
   130  
   131  		DynamoDB *struct {
   132  			// The name of the DynamoDB table to be used as KV
   133  			TableName string `mapstructure:"table_name"`
   134  
   135  			// Maximal number of items per page during scan operation
   136  			ScanLimit int64 `mapstructure:"scan_limit"`
   137  
   138  			// The endpoint URL of the DynamoDB endpoint
   139  			// Can be used to redirect to DynamoDB on AWS, local docker etc.
   140  			Endpoint string `mapstructure:"endpoint"`
   141  
   142  			// AWS connection details - region and credentials
   143  			// This will override any such details that are already exist in the system
   144  			// While in general, AWS region and credentials are configured in the system for AWS usage,
   145  			// these can be used to specify fake values, that cna be used to connect to local DynamoDB,
   146  			// in case there are no credentials configured in the system
   147  			// This is a client requirement as described in section 4 in
   148  			// https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html
   149  			AwsRegion          string       `mapstructure:"aws_region"`
   150  			AwsProfile         string       `mapstructure:"aws_profile"`
   151  			AwsAccessKeyID     SecureString `mapstructure:"aws_access_key_id"`
   152  			AwsSecretAccessKey SecureString `mapstructure:"aws_secret_access_key"`
   153  
   154  			// HealthCheckInterval - Interval to run health check for the DynamoDB instance
   155  			// Won't run when is equal or less than 0.
   156  			HealthCheckInterval time.Duration `mapstructure:"health_check_interval"`
   157  
   158  			// MaxAttempts - Specifies the maximum number attempts to make on a request.
   159  			MaxAttempts int `mapstructure:"max_attempts"`
   160  
   161  			// Maximum amount of connections to DDB. 0 means no limit.
   162  			MaxConnections int `mapstructure:"max_connections"`
   163  		} `mapstructure:"dynamodb"`
   164  
   165  		CosmosDB *struct {
   166  			Key        SecureString `mapstructure:"key"`
   167  			Endpoint   string       `mapstructure:"endpoint"`
   168  			Database   string       `mapstructure:"database"`
   169  			Container  string       `mapstructure:"container"`
   170  			Throughput int32        `mapstructure:"throughput"`
   171  			Autoscale  bool         `mapstructure:"autoscale"`
   172  		} `mapstructure:"cosmosdb"`
   173  	}
   174  
   175  	Auth struct {
   176  		Cache struct {
   177  			Enabled bool          `mapstructure:"enabled"`
   178  			Size    int           `mapstructure:"size"`
   179  			TTL     time.Duration `mapstructure:"ttl"`
   180  			Jitter  time.Duration `mapstructure:"jitter"`
   181  		} `mapstructure:"cache"`
   182  		Encrypt struct {
   183  			SecretKey SecureString `mapstructure:"secret_key" validate:"required"`
   184  		} `mapstructure:"encrypt"`
   185  		API struct {
   186  			// Endpoint for authorization operations
   187  			Endpoint           string        `mapstructure:"endpoint"`
   188  			Token              SecureString  `mapstructure:"token"`
   189  			SupportsInvites    bool          `mapstructure:"supports_invites"`
   190  			HealthCheckTimeout time.Duration `mapstructure:"health_check_timeout"`
   191  			SkipHealthCheck    bool          `mapstructure:"skip_health_check"`
   192  		} `mapstructure:"api"`
   193  		AuthenticationAPI struct {
   194  			// Endpoint for authentication operations
   195  			Endpoint string `mapstructure:"endpoint"`
   196  			// ExternalPrincipalAuth configuration related external principals
   197  			ExternalPrincipalsEnabled bool `mapstructure:"external_principals_enabled"`
   198  		} `mapstructure:"authentication_api"`
   199  		RemoteAuthenticator struct {
   200  			// Enabled if set true will enable remote authentication
   201  			Enabled bool `mapstructure:"enabled"`
   202  			// Endpoint URL of the remote authentication service (e.g. https://my-auth.example.com/auth)
   203  			Endpoint string `mapstructure:"endpoint"`
   204  			// DefaultUserGroup is the default group for the users authenticated by the remote service
   205  			DefaultUserGroup string `mapstructure:"default_user_group"`
   206  			// RequestTimeout timeout for remote authentication requests
   207  			RequestTimeout time.Duration `mapstructure:"request_timeout"`
   208  		} `mapstructure:"remote_authenticator"`
   209  		OIDC                   OIDC                   `mapstructure:"oidc"`
   210  		CookieAuthVerification CookieAuthVerification `mapstructure:"cookie_auth_verification"`
   211  		// LogoutRedirectURL is the URL on which to mount the
   212  		// server-side logout.
   213  		LogoutRedirectURL string        `mapstructure:"logout_redirect_url"`
   214  		LoginDuration     time.Duration `mapstructure:"login_duration"`
   215  		LoginMaxDuration  time.Duration `mapstructure:"login_max_duration"`
   216  		UIConfig          struct {
   217  			RBAC               string   `mapstructure:"rbac"`
   218  			LoginURL           string   `mapstructure:"login_url"`
   219  			LoginFailedMessage string   `mapstructure:"login_failed_message"`
   220  			FallbackLoginURL   *string  `mapstructure:"fallback_login_url"`
   221  			FallbackLoginLabel *string  `mapstructure:"fallback_login_label"`
   222  			LoginCookieNames   []string `mapstructure:"login_cookie_names"`
   223  			LogoutURL          string   `mapstructure:"logout_url"`
   224  		} `mapstructure:"ui_config"`
   225  	} `mapstructure:"auth"`
   226  	Blockstore struct {
   227  		Signing struct {
   228  			SecretKey SecureString `mapstructure:"secret_key" validate:"required"`
   229  		} `mapstructure:"signing"`
   230  		Type                   string  `mapstructure:"type" validate:"required"`
   231  		DefaultNamespacePrefix *string `mapstructure:"default_namespace_prefix"`
   232  		Local                  *struct {
   233  			Path                    string   `mapstructure:"path"`
   234  			ImportEnabled           bool     `mapstructure:"import_enabled"`
   235  			ImportHidden            bool     `mapstructure:"import_hidden"`
   236  			AllowedExternalPrefixes []string `mapstructure:"allowed_external_prefixes"`
   237  		} `mapstructure:"local"`
   238  		S3 *struct {
   239  			S3AuthInfo                    `mapstructure:",squash"`
   240  			Region                        string        `mapstructure:"region"`
   241  			Endpoint                      string        `mapstructure:"endpoint"`
   242  			MaxRetries                    int           `mapstructure:"max_retries"`
   243  			ForcePathStyle                bool          `mapstructure:"force_path_style"`
   244  			DiscoverBucketRegion          bool          `mapstructure:"discover_bucket_region"`
   245  			SkipVerifyCertificateTestOnly bool          `mapstructure:"skip_verify_certificate_test_only"`
   246  			ServerSideEncryption          string        `mapstructure:"server_side_encryption"`
   247  			ServerSideEncryptionKmsKeyID  string        `mapstructure:"server_side_encryption_kms_key_id"`
   248  			PreSignedExpiry               time.Duration `mapstructure:"pre_signed_expiry"`
   249  			DisablePreSigned              bool          `mapstructure:"disable_pre_signed"`
   250  			DisablePreSignedUI            bool          `mapstructure:"disable_pre_signed_ui"`
   251  			DisablePreSignedMultipart     bool          `mapstructure:"disable_pre_signed_multipart"`
   252  			ClientLogRetries              bool          `mapstructure:"client_log_retries"`
   253  			ClientLogRequest              bool          `mapstructure:"client_log_request"`
   254  			WebIdentity                   *struct {
   255  				SessionDuration     time.Duration `mapstructure:"session_duration"`
   256  				SessionExpiryWindow time.Duration `mapstructure:"session_expiry_window"`
   257  			} `mapstructure:"web_identity"`
   258  		} `mapstructure:"s3"`
   259  		Azure *struct {
   260  			TryTimeout       time.Duration `mapstructure:"try_timeout"`
   261  			StorageAccount   string        `mapstructure:"storage_account"`
   262  			StorageAccessKey string        `mapstructure:"storage_access_key"`
   263  			// Deprecated: Value ignored
   264  			AuthMethod         string        `mapstructure:"auth_method"`
   265  			PreSignedExpiry    time.Duration `mapstructure:"pre_signed_expiry"`
   266  			DisablePreSigned   bool          `mapstructure:"disable_pre_signed"`
   267  			DisablePreSignedUI bool          `mapstructure:"disable_pre_signed_ui"`
   268  			// Deprecated: Value ignored
   269  			ChinaCloudDeprecated bool   `mapstructure:"china_cloud"`
   270  			TestEndpointURL      string `mapstructure:"test_endpoint_url"`
   271  			// Domain by default points to Azure default domain blob.core.windows.net, can be set to other Azure domains (China/Gov)
   272  			Domain string `mapstructure:"domain"`
   273  		} `mapstructure:"azure"`
   274  		GS *struct {
   275  			S3Endpoint         string        `mapstructure:"s3_endpoint"`
   276  			CredentialsFile    string        `mapstructure:"credentials_file"`
   277  			CredentialsJSON    string        `mapstructure:"credentials_json"`
   278  			PreSignedExpiry    time.Duration `mapstructure:"pre_signed_expiry"`
   279  			DisablePreSigned   bool          `mapstructure:"disable_pre_signed"`
   280  			DisablePreSignedUI bool          `mapstructure:"disable_pre_signed_ui"`
   281  		} `mapstructure:"gs"`
   282  	} `mapstructure:"blockstore"`
   283  	Committed struct {
   284  		LocalCache struct {
   285  			SizeBytes             int64   `mapstructure:"size_bytes"`
   286  			Dir                   string  `mapstructure:"dir"`
   287  			MaxUploadersPerWriter int     `mapstructure:"max_uploaders_per_writer"`
   288  			RangeProportion       float64 `mapstructure:"range_proportion"`
   289  			MetaRangeProportion   float64 `mapstructure:"metarange_proportion"`
   290  		} `mapstructure:"local_cache"`
   291  		BlockStoragePrefix string `mapstructure:"block_storage_prefix"`
   292  		Permanent          struct {
   293  			MinRangeSizeBytes      uint64  `mapstructure:"min_range_size_bytes"`
   294  			MaxRangeSizeBytes      uint64  `mapstructure:"max_range_size_bytes"`
   295  			RangeRaggednessEntries float64 `mapstructure:"range_raggedness_entries"`
   296  		} `mapstructure:"permanent"`
   297  		SSTable struct {
   298  			Memory struct {
   299  				CacheSizeBytes int64 `mapstructure:"cache_size_bytes"`
   300  			} `mapstructure:"memory"`
   301  		} `mapstructure:"sstable"`
   302  	} `mapstructure:"committed"`
   303  	UGC struct {
   304  		PrepareMaxFileSize int64         `mapstructure:"prepare_max_file_size"`
   305  		PrepareInterval    time.Duration `mapstructure:"prepare_interval"`
   306  	} `mapstructure:"ugc"`
   307  	Graveler struct {
   308  		EnsureReadableRootNamespace bool `mapstructure:"ensure_readable_root_namespace"`
   309  		BatchDBIOTransactionMarkers bool `mapstructure:"batch_dbio_transaction_markers"`
   310  		CompactionSensorThreshold   int  `mapstructure:"compaction_sensor_threshold"`
   311  		RepositoryCache             struct {
   312  			Size   int           `mapstructure:"size"`
   313  			Expiry time.Duration `mapstructure:"expiry"`
   314  			Jitter time.Duration `mapstructure:"jitter"`
   315  		} `mapstructure:"repository_cache"`
   316  		CommitCache struct {
   317  			Size   int           `mapstructure:"size"`
   318  			Expiry time.Duration `mapstructure:"expiry"`
   319  			Jitter time.Duration `mapstructure:"jitter"`
   320  		} `mapstructure:"commit_cache"`
   321  		Background struct {
   322  			RateLimit int `mapstructure:"rate_limit"`
   323  		} `mapstructure:"background"`
   324  		MaxBatchDelay time.Duration `mapstructure:"max_batch_delay"`
   325  	} `mapstructure:"graveler"`
   326  	Gateways struct {
   327  		S3 struct {
   328  			DomainNames       Strings `mapstructure:"domain_name"`
   329  			Region            string  `mapstructure:"region"`
   330  			FallbackURL       string  `mapstructure:"fallback_url"`
   331  			VerifyUnsupported bool    `mapstructure:"verify_unsupported"`
   332  		} `mapstructure:"s3"`
   333  	}
   334  	Stats struct {
   335  		Enabled       bool          `mapstructure:"enabled"`
   336  		Address       string        `mapstructure:"address"`
   337  		FlushInterval time.Duration `mapstructure:"flush_interval"`
   338  		FlushSize     int           `mapstructure:"flush_size"`
   339  		Extended      bool          `mapstructure:"extended"`
   340  	} `mapstructure:"stats"`
   341  	EmailSubscription struct {
   342  		Enabled bool `mapstructure:"enabled"`
   343  	} `mapstructure:"email_subscription"`
   344  	Installation struct {
   345  		FixedID         string       `mapstructure:"fixed_id"`
   346  		UserName        string       `mapstructure:"user_name"`
   347  		AccessKeyID     SecureString `mapstructure:"access_key_id"`
   348  		SecretAccessKey SecureString `mapstructure:"secret_access_key"`
   349  	} `mapstructure:"installation"`
   350  	Security struct {
   351  		CheckLatestVersion      bool          `mapstructure:"check_latest_version"`
   352  		CheckLatestVersionCache time.Duration `mapstructure:"check_latest_version_cache"`
   353  		AuditCheckInterval      time.Duration `mapstructure:"audit_check_interval"`
   354  		AuditCheckURL           string        `mapstructure:"audit_check_url"`
   355  	} `mapstructure:"security"`
   356  	UI struct {
   357  		// Enabled - control serving of embedded UI
   358  		Enabled  bool `mapstructure:"enabled"`
   359  		Snippets []struct {
   360  			ID   string `mapstructure:"id"`
   361  			Code string `mapstructure:"code"`
   362  		} `mapstructure:"snippets"`
   363  	} `mapstructure:"ui"`
   364  	UsageReport struct {
   365  		Enabled       bool          `mapstructure:"enabled"`
   366  		FlushInterval time.Duration `mapstructure:"flush_interval"`
   367  	} `mapstructure:"usage_report"`
   368  }
   369  
   370  func NewConfig(cfgType string) (*Config, error) {
   371  	return newConfig(cfgType)
   372  }
   373  
   374  func newConfig(cfgType string) (*Config, error) {
   375  	c := &Config{}
   376  
   377  	// Inform viper of all expected fields.  Otherwise, it fails to deserialize from the
   378  	// environment.
   379  	keys := GetStructKeys(reflect.TypeOf(c), "mapstructure", "squash")
   380  	for _, key := range keys {
   381  		viper.SetDefault(key, nil)
   382  	}
   383  	setDefaults(cfgType)
   384  
   385  	err := Unmarshal(c)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	err = c.validateDomainNames()
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	// setup logging package
   396  	logging.SetOutputFormat(c.Logging.Format)
   397  	err = logging.SetOutputs(c.Logging.Output, c.Logging.FileMaxSizeMB, c.Logging.FilesKeep)
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  	logging.SetLevel(c.Logging.Level)
   402  	return c, nil
   403  }
   404  
   405  func Unmarshal(c *Config) error {
   406  	return viper.UnmarshalExact(&c,
   407  		viper.DecodeHook(
   408  			mapstructure.ComposeDecodeHookFunc(
   409  				DecodeStrings, mapstructure.StringToTimeDurationHookFunc())))
   410  }
   411  
   412  func stringReverse(s string) string {
   413  	chars := []rune(s)
   414  	for i := 0; i < len(chars)/2; i++ {
   415  		j := len(chars) - 1 - i
   416  		chars[i], chars[j] = chars[j], chars[i]
   417  	}
   418  	return string(chars)
   419  }
   420  
   421  func (c *Config) validateDomainNames() error {
   422  	domainStrings := c.Gateways.S3.DomainNames
   423  	domainNames := make([]string, len(domainStrings))
   424  	copy(domainNames, domainStrings)
   425  	for i, d := range domainNames {
   426  		domainNames[i] = stringReverse(d)
   427  	}
   428  	sort.Strings(domainNames)
   429  	for i, d := range domainNames {
   430  		domainNames[i] = stringReverse(d)
   431  	}
   432  	for i := 0; i < len(domainNames)-1; i++ {
   433  		if strings.HasSuffix(domainNames[i+1], "."+domainNames[i]) {
   434  			return fmt.Errorf("%w: %s, %s", ErrBadDomainNames, domainNames[i], domainNames[i+1])
   435  		}
   436  	}
   437  	return nil
   438  }
   439  
   440  func (c *Config) Validate() error {
   441  	missingKeys := ValidateMissingRequiredKeys(c, "mapstructure", "squash")
   442  	if len(missingKeys) > 0 {
   443  		return fmt.Errorf("%w: %v", ErrMissingRequiredKeys, missingKeys)
   444  	}
   445  	return nil
   446  }
   447  
   448  func (c *Config) BlockstoreType() string {
   449  	return c.Blockstore.Type
   450  }
   451  
   452  func (c *Config) BlockstoreS3Params() (blockparams.S3, error) {
   453  	var webIdentity *blockparams.S3WebIdentity
   454  	if c.Blockstore.S3.WebIdentity != nil {
   455  		webIdentity = &blockparams.S3WebIdentity{
   456  			SessionDuration:     c.Blockstore.S3.WebIdentity.SessionDuration,
   457  			SessionExpiryWindow: c.Blockstore.S3.WebIdentity.SessionExpiryWindow,
   458  		}
   459  	}
   460  
   461  	var creds blockparams.S3Credentials
   462  	if c.Blockstore.S3.Credentials != nil {
   463  		creds.AccessKeyID = c.Blockstore.S3.Credentials.AccessKeyID.SecureValue()
   464  		creds.SecretAccessKey = c.Blockstore.S3.Credentials.SecretAccessKey.SecureValue()
   465  		creds.SessionToken = c.Blockstore.S3.Credentials.SessionToken.SecureValue()
   466  	}
   467  
   468  	return blockparams.S3{
   469  		Region:                        c.Blockstore.S3.Region,
   470  		Profile:                       c.Blockstore.S3.Profile,
   471  		CredentialsFile:               c.Blockstore.S3.CredentialsFile,
   472  		Credentials:                   creds,
   473  		MaxRetries:                    c.Blockstore.S3.MaxRetries,
   474  		Endpoint:                      c.Blockstore.S3.Endpoint,
   475  		ForcePathStyle:                c.Blockstore.S3.ForcePathStyle,
   476  		DiscoverBucketRegion:          c.Blockstore.S3.DiscoverBucketRegion,
   477  		SkipVerifyCertificateTestOnly: c.Blockstore.S3.SkipVerifyCertificateTestOnly,
   478  		ServerSideEncryption:          c.Blockstore.S3.ServerSideEncryption,
   479  		ServerSideEncryptionKmsKeyID:  c.Blockstore.S3.ServerSideEncryptionKmsKeyID,
   480  		PreSignedExpiry:               c.Blockstore.S3.PreSignedExpiry,
   481  		DisablePreSigned:              c.Blockstore.S3.DisablePreSigned,
   482  		DisablePreSignedUI:            c.Blockstore.S3.DisablePreSignedUI,
   483  		DisablePreSignedMultipart:     c.Blockstore.S3.DisablePreSignedMultipart,
   484  		ClientLogRetries:              c.Blockstore.S3.ClientLogRetries,
   485  		ClientLogRequest:              c.Blockstore.S3.ClientLogRequest,
   486  		WebIdentity:                   webIdentity,
   487  	}, nil
   488  }
   489  
   490  func (c *Config) BlockstoreLocalParams() (blockparams.Local, error) {
   491  	localPath := c.Blockstore.Local.Path
   492  	path, err := homedir.Expand(localPath)
   493  	if err != nil {
   494  		return blockparams.Local{}, fmt.Errorf("parse blockstore location URI %s: %w", localPath, err)
   495  	}
   496  
   497  	params := blockparams.Local(*c.Blockstore.Local)
   498  	params.Path = path
   499  	return params, nil
   500  }
   501  
   502  func (c *Config) BlockstoreGSParams() (blockparams.GS, error) {
   503  	credPath, err := homedir.Expand(c.Blockstore.GS.CredentialsFile)
   504  	if err != nil {
   505  		return blockparams.GS{}, fmt.Errorf("parse GS credentials path '%s': %w", c.Blockstore.GS.CredentialsFile, err)
   506  	}
   507  	return blockparams.GS{
   508  		CredentialsFile:    credPath,
   509  		CredentialsJSON:    c.Blockstore.GS.CredentialsJSON,
   510  		PreSignedExpiry:    c.Blockstore.GS.PreSignedExpiry,
   511  		DisablePreSigned:   c.Blockstore.GS.DisablePreSigned,
   512  		DisablePreSignedUI: c.Blockstore.GS.DisablePreSignedUI,
   513  	}, nil
   514  }
   515  
   516  func (c *Config) BlockstoreAzureParams() (blockparams.Azure, error) {
   517  	if c.Blockstore.Azure.AuthMethod != "" {
   518  		logging.ContextUnavailable().Warn("blockstore.azure.auth_method is deprecated. Value is no longer used.")
   519  	}
   520  	if c.Blockstore.Azure.ChinaCloudDeprecated {
   521  		logging.ContextUnavailable().Warn("blockstore.azure.china_cloud is deprecated. Value is no longer used. Please pass Domain = 'blob.core.chinacloudapi.cn'")
   522  		c.Blockstore.Azure.Domain = "blob.core.chinacloudapi.cn"
   523  	}
   524  	return blockparams.Azure{
   525  		StorageAccount:     c.Blockstore.Azure.StorageAccount,
   526  		StorageAccessKey:   c.Blockstore.Azure.StorageAccessKey,
   527  		TryTimeout:         c.Blockstore.Azure.TryTimeout,
   528  		PreSignedExpiry:    c.Blockstore.Azure.PreSignedExpiry,
   529  		TestEndpointURL:    c.Blockstore.Azure.TestEndpointURL,
   530  		Domain:             c.Blockstore.Azure.Domain,
   531  		DisablePreSigned:   c.Blockstore.Azure.DisablePreSigned,
   532  		DisablePreSignedUI: c.Blockstore.Azure.DisablePreSignedUI,
   533  	}, nil
   534  }
   535  
   536  const (
   537  	AuthRBACSimplified = "simplified"
   538  	AuthRBACExternal   = "external"
   539  	AuthRBACInternal   = "internal"
   540  )
   541  
   542  func (c *Config) IsAuthUISimplified() bool {
   543  	return c.Auth.UIConfig.RBAC == AuthRBACSimplified
   544  }
   545  
   546  func (c *Config) IsAuthenticationTypeAPI() bool {
   547  	return c.Auth.AuthenticationAPI.Endpoint != ""
   548  }
   549  func (c *Config) IsAuthTypeAPI() bool {
   550  	return c.Auth.API.Endpoint != ""
   551  }
   552  func (c *Config) IsExternalPrincipalsEnabled() bool {
   553  	// IsAuthTypeAPI must be true since the local auth service doesnt support external principals
   554  	// ExternalPrincipalsEnabled indicates that the remote auth service enables external principals support since its optional extension
   555  	return c.IsAuthTypeAPI() && c.Auth.AuthenticationAPI.ExternalPrincipalsEnabled
   556  }
   557  
   558  func (c *Config) UISnippets() []apiparams.CodeSnippet {
   559  	snippets := make([]apiparams.CodeSnippet, 0, len(c.UI.Snippets))
   560  	for _, item := range c.UI.Snippets {
   561  		snippets = append(snippets, apiparams.CodeSnippet{
   562  			ID:   item.ID,
   563  			Code: item.Code,
   564  		})
   565  	}
   566  	return snippets
   567  }