19896: Configurable minimum TLS version for LDAP connection.
[arvados.git] / sdk / go / arvados / config.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package arvados
6
7 import (
8         "crypto/tls"
9         "encoding/json"
10         "errors"
11         "fmt"
12         "net/url"
13         "os"
14         "time"
15
16         "git.arvados.org/arvados.git/sdk/go/config"
17 )
18
19 var DefaultConfigFile = func() string {
20         if path := os.Getenv("ARVADOS_CONFIG"); path != "" {
21                 return path
22         }
23         return "/etc/arvados/config.yml"
24 }()
25
26 type Config struct {
27         Clusters         map[string]Cluster
28         AutoReloadConfig bool
29         SourceTimestamp  time.Time
30         SourceSHA256     string
31 }
32
33 // GetConfig returns the current system config, loading it from
34 // configFile if needed.
35 func GetConfig(configFile string) (*Config, error) {
36         var cfg Config
37         err := config.LoadFile(&cfg, configFile)
38         return &cfg, err
39 }
40
41 // GetCluster returns the cluster ID and config for the given
42 // cluster, or the default/only configured cluster if clusterID is "".
43 func (sc *Config) GetCluster(clusterID string) (*Cluster, error) {
44         if clusterID == "" {
45                 if len(sc.Clusters) == 0 {
46                         return nil, fmt.Errorf("no clusters configured")
47                 } else if len(sc.Clusters) > 1 {
48                         return nil, fmt.Errorf("multiple clusters configured, cannot choose")
49                 } else {
50                         for id, cc := range sc.Clusters {
51                                 cc.ClusterID = id
52                                 return &cc, nil
53                         }
54                 }
55         }
56         cc, ok := sc.Clusters[clusterID]
57         if !ok {
58                 return nil, fmt.Errorf("cluster %q is not configured", clusterID)
59         }
60         cc.ClusterID = clusterID
61         return &cc, nil
62 }
63
64 type WebDAVCacheConfig struct {
65         TTL                Duration
66         MaxBlockEntries    int
67         MaxCollectionBytes int64
68         MaxSessions        int
69 }
70
71 type UploadDownloadPermission struct {
72         Upload   bool
73         Download bool
74 }
75
76 type UploadDownloadRolePermissions struct {
77         User  UploadDownloadPermission
78         Admin UploadDownloadPermission
79 }
80
81 type ManagedProperties map[string]struct {
82         Value     interface{}
83         Function  string
84         Protected bool
85 }
86
87 type Cluster struct {
88         ClusterID       string `json:"-"`
89         ManagementToken string
90         SystemRootToken string
91         Services        Services
92         InstanceTypes   InstanceTypeMap
93         Containers      ContainersConfig
94         RemoteClusters  map[string]RemoteCluster
95         PostgreSQL      PostgreSQL
96
97         API struct {
98                 AsyncPermissionsUpdateInterval   Duration
99                 DisabledAPIs                     StringSet
100                 MaxIndexDatabaseRead             int
101                 MaxItemsPerResponse              int
102                 MaxConcurrentRequests            int
103                 MaxKeepBlobBuffers               int
104                 MaxRequestAmplification          int
105                 MaxRequestSize                   int
106                 MaxTokenLifetime                 Duration
107                 RequestTimeout                   Duration
108                 SendTimeout                      Duration
109                 WebsocketClientEventQueue        int
110                 WebsocketServerEventQueue        int
111                 KeepServiceRequestTimeout        Duration
112                 VocabularyPath                   string
113                 FreezeProjectRequiresDescription bool
114                 FreezeProjectRequiresProperties  StringSet
115                 UnfreezeProjectRequiresAdmin     bool
116         }
117         AuditLogs struct {
118                 MaxAge             Duration
119                 MaxDeleteBatch     int
120                 UnloggedAttributes StringSet
121         }
122         Collections struct {
123                 BlobSigning                  bool
124                 BlobSigningKey               string
125                 BlobSigningTTL               Duration
126                 BlobTrash                    bool
127                 BlobTrashLifetime            Duration
128                 BlobTrashCheckInterval       Duration
129                 BlobTrashConcurrency         int
130                 BlobDeleteConcurrency        int
131                 BlobReplicateConcurrency     int
132                 CollectionVersioning         bool
133                 DefaultTrashLifetime         Duration
134                 DefaultReplication           int
135                 ManagedProperties            ManagedProperties
136                 PreserveVersionIfIdle        Duration
137                 TrashSweepInterval           Duration
138                 TrustAllContent              bool
139                 ForwardSlashNameSubstitution string
140                 S3FolderObjects              bool
141
142                 BlobMissingReport        string
143                 BalancePeriod            Duration
144                 BalanceCollectionBatch   int
145                 BalanceCollectionBuffers int
146                 BalanceTimeout           Duration
147                 BalanceUpdateLimit       int
148
149                 WebDAVCache WebDAVCacheConfig
150
151                 KeepproxyPermission UploadDownloadRolePermissions
152                 WebDAVPermission    UploadDownloadRolePermissions
153                 WebDAVLogEvents     bool
154         }
155         Git struct {
156                 GitCommand   string
157                 GitoliteHome string
158                 Repositories string
159         }
160         Login struct {
161                 LDAP struct {
162                         Enable             bool
163                         URL                URL
164                         StartTLS           bool
165                         InsecureTLS        bool
166                         MinTLSVersion      TLSVersion
167                         StripDomain        string
168                         AppendDomain       string
169                         SearchAttribute    string
170                         SearchBindUser     string
171                         SearchBindPassword string
172                         SearchBase         string
173                         SearchFilters      string
174                         EmailAttribute     string
175                         UsernameAttribute  string
176                 }
177                 Google struct {
178                         Enable                          bool
179                         ClientID                        string
180                         ClientSecret                    string
181                         AlternateEmailAddresses         bool
182                         AuthenticationRequestParameters map[string]string
183                 }
184                 OpenIDConnect struct {
185                         Enable                          bool
186                         Issuer                          string
187                         ClientID                        string
188                         ClientSecret                    string
189                         EmailClaim                      string
190                         EmailVerifiedClaim              string
191                         UsernameClaim                   string
192                         AcceptAccessToken               bool
193                         AcceptAccessTokenScope          string
194                         AuthenticationRequestParameters map[string]string
195                 }
196                 PAM struct {
197                         Enable             bool
198                         Service            string
199                         DefaultEmailDomain string
200                 }
201                 Test struct {
202                         Enable bool
203                         Users  map[string]TestUser
204                 }
205                 LoginCluster         string
206                 RemoteTokenRefresh   Duration
207                 TokenLifetime        Duration
208                 TrustedClients       map[URL]struct{}
209                 TrustPrivateNetworks bool
210                 IssueTrustedTokens   bool
211         }
212         Mail struct {
213                 MailchimpAPIKey                string
214                 MailchimpListID                string
215                 SendUserSetupNotificationEmail bool
216                 IssueReporterEmailFrom         string
217                 IssueReporterEmailTo           string
218                 SupportEmailAddress            string
219                 EmailFrom                      string
220         }
221         SystemLogs struct {
222                 LogLevel                string
223                 Format                  string
224                 MaxRequestLogParamsSize int
225         }
226         TLS struct {
227                 Certificate string
228                 Key         string
229                 Insecure    bool
230                 ACME        struct {
231                         Server string
232                 }
233         }
234         Users struct {
235                 ActivatedUsersAreVisibleToOthers      bool
236                 AnonymousUserToken                    string
237                 AdminNotifierEmailFrom                string
238                 AutoAdminFirstUser                    bool
239                 AutoAdminUserWithEmail                string
240                 AutoSetupNewUsers                     bool
241                 AutoSetupNewUsersWithRepository       bool
242                 AutoSetupNewUsersWithVmUUID           string
243                 AutoSetupUsernameBlacklist            StringSet
244                 EmailSubjectPrefix                    string
245                 NewInactiveUserNotificationRecipients StringSet
246                 NewUserNotificationRecipients         StringSet
247                 NewUsersAreActive                     bool
248                 UserNotifierEmailFrom                 string
249                 UserNotifierEmailBcc                  StringSet
250                 UserProfileNotificationAddress        string
251                 PreferDomainForUsername               string
252                 UserSetupMailText                     string
253                 RoleGroupsVisibleToAll                bool
254                 CanCreateRoleGroups                   bool
255                 ActivityLoggingPeriod                 Duration
256         }
257         StorageClasses map[string]StorageClassConfig
258         Volumes        map[string]Volume
259         Workbench      struct {
260                 ActivationContactLink            string
261                 APIClientConnectTimeout          Duration
262                 APIClientReceiveTimeout          Duration
263                 APIResponseCompression           bool
264                 ApplicationMimetypesWithViewIcon StringSet
265                 ArvadosDocsite                   string
266                 ArvadosPublicDataDocURL          string
267                 DefaultOpenIdPrefix              string
268                 DisableSharingURLsUI             bool
269                 EnableGettingStartedPopup        bool
270                 EnablePublicProjectsPage         bool
271                 FileViewersConfigURL             string
272                 LogViewerMaxBytes                ByteSize
273                 MultiSiteSearch                  string
274                 ProfilingEnabled                 bool
275                 Repositories                     bool
276                 RepositoryCache                  string
277                 RunningJobLogRecordsToFetch      int
278                 SecretKeyBase                    string
279                 ShowRecentCollectionsOnDashboard bool
280                 ShowUserAgreementInline          bool
281                 ShowUserNotifications            bool
282                 SiteName                         string
283                 Theme                            string
284                 UserProfileFormFields            map[string]struct {
285                         Type                 string
286                         FormFieldTitle       string
287                         FormFieldDescription string
288                         Required             bool
289                         Position             int
290                         Options              map[string]struct{}
291                 }
292                 UserProfileFormMessage string
293                 WelcomePageHTML        string
294                 InactivePageHTML       string
295                 SSHHelpPageHTML        string
296                 SSHHelpHostSuffix      string
297                 IdleTimeout            Duration
298                 BannerURL              string
299         }
300 }
301
302 type StorageClassConfig struct {
303         Default  bool
304         Priority int
305 }
306
307 type Volume struct {
308         AccessViaHosts   map[URL]VolumeAccess
309         ReadOnly         bool
310         Replication      int
311         StorageClasses   map[string]bool
312         Driver           string
313         DriverParameters json.RawMessage
314 }
315
316 type S3VolumeDriverParameters struct {
317         IAMRole            string
318         AccessKeyID        string
319         SecretAccessKey    string
320         Endpoint           string
321         Region             string
322         Bucket             string
323         LocationConstraint bool
324         V2Signature        bool
325         UseAWSS3v2Driver   bool
326         IndexPageSize      int
327         ConnectTimeout     Duration
328         ReadTimeout        Duration
329         RaceWindow         Duration
330         UnsafeDelete       bool
331         PrefixLength       int
332 }
333
334 type AzureVolumeDriverParameters struct {
335         StorageAccountName   string
336         StorageAccountKey    string
337         StorageBaseURL       string
338         ContainerName        string
339         RequestTimeout       Duration
340         ListBlobsRetryDelay  Duration
341         ListBlobsMaxAttempts int
342 }
343
344 type DirectoryVolumeDriverParameters struct {
345         Root      string
346         Serialize bool
347 }
348
349 type VolumeAccess struct {
350         ReadOnly bool
351 }
352
353 type Services struct {
354         Composer       Service
355         Controller     Service
356         DispatchCloud  Service
357         DispatchLSF    Service
358         DispatchSLURM  Service
359         GitHTTP        Service
360         GitSSH         Service
361         Health         Service
362         Keepbalance    Service
363         Keepproxy      Service
364         Keepstore      Service
365         RailsAPI       Service
366         WebDAVDownload Service
367         WebDAV         Service
368         WebShell       Service
369         Websocket      Service
370         Workbench1     Service
371         Workbench2     Service
372 }
373
374 type Service struct {
375         InternalURLs map[URL]ServiceInstance
376         ExternalURL  URL
377 }
378
379 type TestUser struct {
380         Email    string
381         Password string
382 }
383
384 // URL is a url.URL that is also usable as a JSON key/value.
385 type URL url.URL
386
387 // UnmarshalText implements encoding.TextUnmarshaler so URL can be
388 // used as a JSON key/value.
389 func (su *URL) UnmarshalText(text []byte) error {
390         u, err := url.Parse(string(text))
391         if err == nil {
392                 *su = URL(*u)
393                 if su.Path == "" && su.Host != "" {
394                         // http://example really means http://example/
395                         su.Path = "/"
396                 }
397         }
398         return err
399 }
400
401 func (su URL) MarshalText() ([]byte, error) {
402         return []byte(su.String()), nil
403 }
404
405 func (su URL) String() string {
406         return (*url.URL)(&su).String()
407 }
408
409 type TLSVersion uint16
410
411 func (v TLSVersion) MarshalText() ([]byte, error) {
412         switch v {
413         case 0:
414                 return []byte{}, nil
415         case tls.VersionTLS10:
416                 return []byte("1.0"), nil
417         case tls.VersionTLS11:
418                 return []byte("1.1"), nil
419         case tls.VersionTLS12:
420                 return []byte("1.2"), nil
421         case tls.VersionTLS13:
422                 return []byte("1.3"), nil
423         default:
424                 return nil, fmt.Errorf("unsupported TLSVersion %x", v)
425         }
426 }
427
428 func (v *TLSVersion) UnmarshalJSON(text []byte) error {
429         if len(text) > 0 && text[0] == '"' {
430                 var s string
431                 err := json.Unmarshal(text, &s)
432                 if err != nil {
433                         return err
434                 }
435                 text = []byte(s)
436         }
437         switch string(text) {
438         case "":
439                 *v = 0
440         case "1.0":
441                 *v = tls.VersionTLS10
442         case "1.1":
443                 *v = tls.VersionTLS11
444         case "1.2":
445                 *v = tls.VersionTLS12
446         case "1.3":
447                 *v = tls.VersionTLS13
448         default:
449                 return fmt.Errorf("unsupported TLSVersion %q", text)
450         }
451         return nil
452 }
453
454 type ServiceInstance struct {
455         ListenURL  URL
456         Rendezvous string `json:",omitempty"`
457 }
458
459 type PostgreSQL struct {
460         Connection     PostgreSQLConnection
461         ConnectionPool int
462 }
463
464 type PostgreSQLConnection map[string]string
465
466 type RemoteCluster struct {
467         Host          string
468         Proxy         bool
469         Scheme        string
470         Insecure      bool
471         ActivateUsers bool
472 }
473
474 type CUDAFeatures struct {
475         DriverVersion      string
476         HardwareCapability string
477         DeviceCount        int
478 }
479
480 type InstanceType struct {
481         Name            string `json:"-"`
482         ProviderType    string
483         VCPUs           int
484         RAM             ByteSize
485         Scratch         ByteSize `json:"-"`
486         IncludedScratch ByteSize
487         AddedScratch    ByteSize
488         Price           float64
489         Preemptible     bool
490         CUDA            CUDAFeatures
491 }
492
493 type ContainersConfig struct {
494         CloudVMs                      CloudVMsConfig
495         CrunchRunCommand              string
496         CrunchRunArgumentsList        []string
497         DefaultKeepCacheRAM           ByteSize
498         DispatchPrivateKey            string
499         LogReuseDecisions             bool
500         MaxComputeVMs                 int
501         MaxDispatchAttempts           int
502         MaxRetryAttempts              int
503         MinRetryPeriod                Duration
504         ReserveExtraRAM               ByteSize
505         StaleLockTimeout              Duration
506         SupportedDockerImageFormats   StringSet
507         AlwaysUsePreemptibleInstances bool
508         PreemptiblePriceFactor        float64
509         RuntimeEngine                 string
510         LocalKeepBlobBuffersPerVCPU   int
511         LocalKeepLogsToContainerLog   string
512
513         JobsAPI struct {
514                 Enable         string
515                 GitInternalDir string
516         }
517         Logging struct {
518                 MaxAge                       Duration
519                 SweepInterval                Duration
520                 LogBytesPerEvent             int
521                 LogSecondsBetweenEvents      Duration
522                 LogThrottlePeriod            Duration
523                 LogThrottleBytes             int
524                 LogThrottleLines             int
525                 LimitLogBytesPerJob          int
526                 LogPartialLineThrottlePeriod Duration
527                 LogUpdatePeriod              Duration
528                 LogUpdateSize                ByteSize
529         }
530         ShellAccess struct {
531                 Admin bool
532                 User  bool
533         }
534         SLURM struct {
535                 PrioritySpread             int64
536                 SbatchArgumentsList        []string
537                 SbatchEnvironmentVariables map[string]string
538                 Managed                    struct {
539                         DNSServerConfDir       string
540                         DNSServerConfTemplate  string
541                         DNSServerReloadCommand string
542                         DNSServerUpdateCommand string
543                         ComputeNodeDomain      string
544                         ComputeNodeNameservers StringSet
545                         AssignNodeHostname     string
546                 }
547         }
548         LSF struct {
549                 BsubSudoUser      string
550                 BsubArgumentsList []string
551                 BsubCUDAArguments []string
552         }
553 }
554
555 type CloudVMsConfig struct {
556         Enable bool
557
558         BootProbeCommand               string
559         DeployRunnerBinary             string
560         ImageID                        string
561         MaxCloudOpsPerSecond           int
562         MaxProbesPerSecond             int
563         MaxConcurrentInstanceCreateOps int
564         PollInterval                   Duration
565         ProbeInterval                  Duration
566         SSHPort                        string
567         SyncInterval                   Duration
568         TimeoutBooting                 Duration
569         TimeoutIdle                    Duration
570         TimeoutProbe                   Duration
571         TimeoutShutdown                Duration
572         TimeoutSignal                  Duration
573         TimeoutStaleRunLock            Duration
574         TimeoutTERM                    Duration
575         ResourceTags                   map[string]string
576         TagKeyPrefix                   string
577
578         Driver           string
579         DriverParameters json.RawMessage
580 }
581
582 type InstanceTypeMap map[string]InstanceType
583
584 var errDuplicateInstanceTypeName = errors.New("duplicate instance type name")
585
586 // UnmarshalJSON does special handling of InstanceTypes:
587 //
588 // - populate computed fields (Name and Scratch)
589 //
590 // - error out if InstancesTypes are populated as an array, which was
591 // deprecated in Arvados 1.2.0
592 func (it *InstanceTypeMap) UnmarshalJSON(data []byte) error {
593         fixup := func(t InstanceType) (InstanceType, error) {
594                 if t.ProviderType == "" {
595                         t.ProviderType = t.Name
596                 }
597                 // If t.Scratch is set in the configuration file, it will be ignored and overwritten.
598                 // It will also generate a "deprecated or unknown config entry" warning.
599                 t.Scratch = t.IncludedScratch + t.AddedScratch
600                 return t, nil
601         }
602
603         if len(data) > 0 && data[0] == '[' {
604                 return fmt.Errorf("InstanceTypes must be specified as a map, not an array, see https://doc.arvados.org/admin/config.html")
605         }
606         var hash map[string]InstanceType
607         err := json.Unmarshal(data, &hash)
608         if err != nil {
609                 return err
610         }
611         // Fill in Name field (and ProviderType field, if not
612         // specified) using hash key.
613         *it = InstanceTypeMap(hash)
614         for name, t := range *it {
615                 t.Name = name
616                 t, err := fixup(t)
617                 if err != nil {
618                         return err
619                 }
620                 (*it)[name] = t
621         }
622         return nil
623 }
624
625 type StringSet map[string]struct{}
626
627 // UnmarshalJSON handles old config files that provide an array of
628 // instance types instead of a hash.
629 func (ss *StringSet) UnmarshalJSON(data []byte) error {
630         if len(data) > 0 && data[0] == '[' {
631                 var arr []string
632                 err := json.Unmarshal(data, &arr)
633                 if err != nil {
634                         return err
635                 }
636                 if len(arr) == 0 {
637                         *ss = nil
638                         return nil
639                 }
640                 *ss = make(map[string]struct{}, len(arr))
641                 for _, t := range arr {
642                         (*ss)[t] = struct{}{}
643                 }
644                 return nil
645         }
646         var hash map[string]struct{}
647         err := json.Unmarshal(data, &hash)
648         if err != nil {
649                 return err
650         }
651         *ss = make(map[string]struct{}, len(hash))
652         for t := range hash {
653                 (*ss)[t] = struct{}{}
654         }
655
656         return nil
657 }
658
659 type ServiceName string
660
661 const (
662         ServiceNameController    ServiceName = "arvados-controller"
663         ServiceNameDispatchCloud ServiceName = "arvados-dispatch-cloud"
664         ServiceNameDispatchLSF   ServiceName = "arvados-dispatch-lsf"
665         ServiceNameDispatchSLURM ServiceName = "crunch-dispatch-slurm"
666         ServiceNameGitHTTP       ServiceName = "arvados-git-httpd"
667         ServiceNameHealth        ServiceName = "arvados-health"
668         ServiceNameKeepbalance   ServiceName = "keep-balance"
669         ServiceNameKeepproxy     ServiceName = "keepproxy"
670         ServiceNameKeepstore     ServiceName = "keepstore"
671         ServiceNameKeepweb       ServiceName = "keep-web"
672         ServiceNameRailsAPI      ServiceName = "arvados-api-server"
673         ServiceNameWebsocket     ServiceName = "arvados-ws"
674         ServiceNameWorkbench1    ServiceName = "arvados-workbench1"
675         ServiceNameWorkbench2    ServiceName = "arvados-workbench2"
676 )
677
678 // Map returns all services as a map, suitable for iterating over all
679 // services or looking up a service by name.
680 func (svcs Services) Map() map[ServiceName]Service {
681         return map[ServiceName]Service{
682                 ServiceNameController:    svcs.Controller,
683                 ServiceNameDispatchCloud: svcs.DispatchCloud,
684                 ServiceNameDispatchLSF:   svcs.DispatchLSF,
685                 ServiceNameDispatchSLURM: svcs.DispatchSLURM,
686                 ServiceNameGitHTTP:       svcs.GitHTTP,
687                 ServiceNameHealth:        svcs.Health,
688                 ServiceNameKeepbalance:   svcs.Keepbalance,
689                 ServiceNameKeepproxy:     svcs.Keepproxy,
690                 ServiceNameKeepstore:     svcs.Keepstore,
691                 ServiceNameKeepweb:       svcs.WebDAV,
692                 ServiceNameRailsAPI:      svcs.RailsAPI,
693                 ServiceNameWebsocket:     svcs.Websocket,
694                 ServiceNameWorkbench1:    svcs.Workbench1,
695                 ServiceNameWorkbench2:    svcs.Workbench2,
696         }
697 }