2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								/ *  
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								 *  MinIO  Cloud  Storage ,  ( C )  2017 - 2019  MinIO ,  Inc . 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Licensed  under  the  Apache  License ,  Version  2.0  ( the  "License" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  you  may  not  use  this  file  except  in  compliance  with  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  You  may  obtain  a  copy  of  the  License  at 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *      http : //www.apache.org/licenses/LICENSE-2.0
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  Unless  required  by  applicable  law  or  agreed  to  in  writing ,  software 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  distributed  under  the  License  is  distributed  on  an  "AS IS"  BASIS , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  WITHOUT  WARRANTIES  OR  CONDITIONS  OF  ANY  KIND ,  either  express  or  implied . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  See  the  License  for  the  specific  language  governing  permissions  and 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 *  limitations  under  the  License . 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								 * / 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								package  cmd  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
									
										
										
										
											2021-01-24 10:27:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"context" 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"crypto/x509" 
							 
						 
					
						
							
								
									
										
										
										
											2020-02-07 16:18:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"encoding/gob" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-19 16:34:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"math/rand" 
							 
						 
					
						
							
								
									
										
										
										
											2018-02-03 10:18:52 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"net" 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-23 23:03:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"net/url" 
							 
						 
					
						
							
								
									
										
										
										
											2020-03-18 01:36:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"os" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"path/filepath" 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-23 23:03:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"runtime" 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 03:44:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 08:52:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/fatih/color" 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-21 05:56:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									dns2  "github.com/miekg/dns" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"github.com/minio/cli" 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-15 00:38:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio-go/v7/pkg/set" 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-05 01:35:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/cmd/config" 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-19 16:34:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									xhttp  "github.com/minio/minio/cmd/http" 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-06 06:04:40 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/cmd/logger" 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-02 06:53:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/pkg/auth" 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/pkg/certs" 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 08:52:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/pkg/console" 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-05 01:35:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/pkg/env" 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-23 07:37:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"github.com/minio/minio/pkg/handlers" 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 08:52:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								// serverDebugLog will enable debug printing
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  serverDebugLog  =  env . Get ( "_MINIO_SERVER_DEBUG" ,  config . EnableOff )  ==  config . EnableOn  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-02-07 16:18:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  init ( )  {  
						 
					
						
							
								
									
										
										
										
											2021-02-18 04:04:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									rand . Seed ( time . Now ( ) . UTC ( ) . UnixNano ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-02-07 16:18:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									logger . Init ( GOPATH ,  GOROOT ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									logger . RegisterError ( config . FmtError ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-02-18 04:04:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Inject into config package.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									config . Logger . Info  =  logger . Info 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									config . Logger . LogIf  =  logger . LogIf 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-23 07:37:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-04-09 08:51:59 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  IsKubernetes ( )  ||  IsDocker ( )  ||  IsBOSH ( )  ||  IsDCOS ( )  ||  IsKubernetesReplicaSet ( )  ||  IsPCFTile ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// 30 seconds matches the orchestrator DNS TTLs, have
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// a 5 second timeout to lookup from DNS servers.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalDNSCache  =  xhttp . NewDNSCache ( 30 * time . Second ,  5 * time . Second ,  logger . LogOnceIf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// On bare-metals DNS do not change often, so it is
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// safe to assume a higher timeout upto 10 minutes.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalDNSCache  =  xhttp . NewDNSCache ( 10 * time . Minute ,  5 * time . Second ,  logger . LogOnceIf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-10-19 16:34:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-14 03:57:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									initGlobalContext ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-23 07:37:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalForwarder  =  handlers . NewForwarder ( & handlers . Forwarder { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										PassHost :      true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										RoundTripper :  newGatewayHTTPTransport ( 1  *  time . Hour ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Logger :  func ( err  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-24 10:27:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  err  !=  nil  &&  ! errors . Is ( err ,  context . Canceled )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												logger . LogIf ( GlobalContext ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-23 07:37:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-14 03:57:08 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalTransitionState  =  newTransitionState ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-18 08:52:47 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									console . SetColor ( "Debug" ,  color . New ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-02-07 16:18:07 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									gob . Register ( StorageErr ( "" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-07-26 17:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  verifyObjectLayerFeatures ( name  string ,  objAPI  ObjectLayer )  {  
						 
					
						
							
								
									
										
										
										
											2020-09-04 03:43:45 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ( GlobalKMS  !=  nil )  &&  ! objAPI . IsEncryptionSupported ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-26 17:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										logger . Fatal ( errInvalidArgument , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Encryption support is requested but '%s' does not support encryption" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  strings . HasPrefix ( name ,  "gateway" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  GlobalGatewaySSE . IsSet ( )  &&  GlobalKMS  ==  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-05 01:35:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											uiErr  :=  config . ErrInvalidGWSSEEnvValue ( nil ) . Msg ( "MINIO_GATEWAY_SSE set but KMS is not configured" ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-26 17:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . Fatal ( uiErr ,  "Unable to start gateway with SSE" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-12-05 01:32:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalCompressConfigMu . Lock ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-23 13:59:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  globalCompressConfig . Enabled  &&  ! objAPI . IsCompressionSupported ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-26 17:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										logger . Fatal ( errInvalidArgument , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Compression support is requested but '%s' does not support compression" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-05 01:32:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalCompressConfigMu . Unlock ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-07-26 17:41:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								// Check for updates and print a notification message
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  checkUpdate ( mode  string )  {  
						 
					
						
							
								
									
										
										
										
											2020-07-23 23:03:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									updateURL  :=  minioReleaseInfoURL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  runtime . GOOS  ==  globalWindowsOSName  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										updateURL  =  minioReleaseWindowsInfoURL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									u ,  err  :=  url . Parse ( updateURL ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-16 04:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Its OK to ignore any errors during doUpdate() here.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-23 23:03:31 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									crTime ,  err  :=  GetCurrentReleaseTime ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									_ ,  lrTime ,  err  :=  getLatestReleaseTime ( u ,  2 * time . Second ,  mode ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  older  time . Duration 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  downloadURL  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  lrTime . After ( crTime )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										older  =  lrTime . Sub ( crTime ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										downloadURL  =  getDownloadURL ( releaseTimeToReleaseTag ( lrTime ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									updateMsg  :=  prepareUpdateMessage ( downloadURL ,  older ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  updateMsg  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-10-25 13:39:44 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									logStartupMessage ( prepareUpdateMessage ( "Run `mc admin update`" ,  lrTime . Sub ( crTime ) ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  newConfigDirFromCtx ( ctx  * cli . Context ,  option  string ,  getDefaultDir  func ( )  string )  ( * ConfigDir ,  bool )  {  
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  dir  string 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  dirSet  bool 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  ctx . IsSet ( option ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dir  =  ctx . String ( option ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										dirSet  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									case  ctx . GlobalIsSet ( option ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dir  =  ctx . GlobalString ( option ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										dirSet  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// cli package does not expose parent's option option.  Below code is workaround.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  dir  ==  ""  ||  dir  ==  getDefaultDir ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											dirSet  =  false  // Unset to false since GlobalIsSet() true is a false positive.
 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  ctx . Parent ( ) . GlobalIsSet ( option )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												dir  =  ctx . Parent ( ) . GlobalString ( option ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												dirSet  =  true 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Neither local nor global option is provided.  In this case, try to use
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// default directory.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dir  =  getDefaultDir ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  dir  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . FatalIf ( errInvalidArgument ,  "%s option must be provided" ,  option ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  dir  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . FatalIf ( errors . New ( "empty directory" ) ,  "%s directory cannot be empty" ,  option ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Disallow relative paths, figure out absolute paths.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dirAbs ,  err  :=  filepath . Abs ( dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									logger . FatalIf ( err ,  "Unable to fetch absolute path for %s=%s" ,  option ,  dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									logger . FatalIf ( mkdirAllIgnorePerm ( dirAbs ) ,  "Unable to create directory specified %s=%s" ,  option ,  dir ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  & ConfigDir { path :  dirAbs } ,  dirSet 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								func  handleCommonCmdArgs ( ctx  * cli . Context )  {  
						 
					
						
							
								
									
										
										
										
											2018-03-01 12:13:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2018-12-19 08:08:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Get "json" flag from command line argument and
 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-10 21:49:00 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// enable json and quite modes if json flag is turned on.
 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-19 08:08:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalCLIContext . JSON  =  ctx . IsSet ( "json" )  ||  ctx . GlobalIsSet ( "json" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  globalCLIContext . JSON  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . EnableJSON ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Get quiet flag from command line argument.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalCLIContext . Quiet  =  ctx . IsSet ( "quiet" )  ||  ctx . GlobalIsSet ( "quiet" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  globalCLIContext . Quiet  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . EnableQuiet ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Get anonymous flag from command line argument.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalCLIContext . Anonymous  =  ctx . IsSet ( "anonymous" )  ||  ctx . GlobalIsSet ( "anonymous" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  globalCLIContext . Anonymous  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . EnableAnonymous ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Fetch address option
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalCLIContext . Addr  =  ctx . GlobalString ( "address" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-17 23:46:23 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  globalCLIContext . Addr  ==  ""  ||  globalCLIContext . Addr  ==  ":" + GlobalMinioDefaultPort  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-19 08:08:11 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										globalCLIContext . Addr  =  ctx . String ( "address" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-04-13 09:08:27 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Check "no-compat" flag from command line argument.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalCLIContext . StrictS3Compat  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ctx . IsSet ( "no-compat" )  ||  ctx . GlobalIsSet ( "no-compat" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalCLIContext . StrictS3Compat  =  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// Set all config, certs and CAs directories.
 
							 
						 
					
						
							
								
									
										
										
										
											2019-01-17 04:04:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									var  configSet ,  certsSet  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalConfigDir ,  configSet  =  newConfigDirFromCtx ( ctx ,  "config-dir" ,  defaultConfigDir . Get ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									globalCertsDir ,  certsSet  =  newConfigDirFromCtx ( ctx ,  "certs-dir" ,  defaultCertsDir . Get ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Remove this code when we deprecate and remove config-dir.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// This code is to make sure we inherit from the config-dir
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// option if certs-dir is not provided.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! certsSet  &&  configSet  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalCertsDir  =  & ConfigDir { path :  filepath . Join ( globalConfigDir . Get ( ) ,  certsDir ) } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalCertsCADir  =  & ConfigDir { path :  filepath . Join ( globalCertsDir . Get ( ) ,  certsCADir ) } 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-01 12:13:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-01-03 02:05:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									logger . FatalIf ( mkdirAllIgnorePerm ( globalCertsCADir . Get ( ) ) ,  "Unable to create certs CA directory at %s" ,  globalCertsCADir . Get ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  handleCommonEnvVars ( )  {  
						 
					
						
							
								
									
										
										
										
											2020-04-25 07:37:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									wormEnabled ,  err  :=  config . LookupWorm ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrInvalidWormValue ( err ) ,  "Invalid worm configuration" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  wormEnabled  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . Fatal ( errors . New ( "WORM is deprecated" ) ,  "global MINIO_WORM support is removed, please downgrade your server or migrate to https://github.com/minio/minio/tree/master/docs/retention" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-12-05 07:32:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalBrowserEnabled ,  err  =  config . ParseBool ( env . Get ( config . EnvBrowser ,  config . EnableOn ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-23 13:59:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrInvalidBrowserValue ( err ) ,  "Invalid MINIO_BROWSER value in environment variable" ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-25 10:04:51 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-13 10:24:59 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalFSOSync ,  err  =  config . ParseBool ( env . Get ( config . EnvFSOSync ,  config . EnableOff ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										logger . Fatal ( config . ErrInvalidFSOSyncValue ( err ) ,  "Invalid MINIO_FS_OSYNC value in environment variable" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-31 14:39:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									domains  :=  env . Get ( config . EnvDomain ,  "" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( domains )  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  domainName  :=  range  strings . Split ( domains ,  config . ValueSeparator )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  _ ,  ok  :=  dns2 . IsDomainName ( domainName ) ;  ! ok  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-05 01:35:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												logger . Fatal ( config . ErrInvalidDomainValue ( nil ) . Msg ( "Unknown value `%s`" ,  domainName ) , 
							 
						 
					
						
							
								
									
										
										
										
											2019-02-23 11:18:01 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													"Invalid MINIO_DOMAIN value in environment variable" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											globalDomainNames  =  append ( globalDomainNames ,  domainName ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-21 05:56:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 03:44:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										sort . Strings ( globalDomainNames ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										lcpSuf  :=  lcpSuffix ( globalDomainNames ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  domainName  :=  range  globalDomainNames  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 05:08:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  domainName  ==  lcpSuf  &&  len ( globalDomainNames )  >  1  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 03:44:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												logger . Fatal ( config . ErrOverlappingDomainValue ( nil ) . Msg ( "Overlapping domains `%s` not allowed" ,  globalDomainNames ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													"Invalid MINIO_DOMAIN value in environment variable" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2018-09-21 05:56:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-05-16 09:20:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-31 14:39:09 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									publicIPs  :=  env . Get ( config . EnvPublicIPs ,  "" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( publicIPs )  !=  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										minioEndpoints  :=  strings . Split ( publicIPs ,  config . ValueSeparator ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-23 19:08:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										var  domainIPs  =  set . NewStringSet ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  endpoint  :=  range  minioEndpoints  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  net . ParseIP ( endpoint )  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// Checking if the IP is a DNS entry.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												addrs ,  err  :=  net . LookupHost ( endpoint ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-04-10 02:39:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
													logger . FatalIf ( err ,  "Unable to initialize MinIO server with [%s] invalid entry found in MINIO_PUBLIC_IPS" ,  endpoint ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-23 19:08:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												for  _ ,  addr  :=  range  addrs  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													domainIPs . Add ( addr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
									
										
										
										
											2018-05-12 03:02:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-23 19:08:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											domainIPs . Add ( endpoint ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-05-12 03:02:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-23 19:08:21 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										updateDomainIPs ( domainIPs ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-05 09:35:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// Add found interfaces IP address to global domain IPS,
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// loopback addresses will be naturally dropped.
 
							 
						 
					
						
							
								
									
										
										
										
											2020-07-21 03:28:48 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										domainIPs  :=  mustGetLocalIP4 ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  host  :=  range  globalEndpoints . Hostnames ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											domainIPs . Add ( host ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										updateDomainIPs ( domainIPs ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-05-12 03:02:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2018-12-05 09:35:22 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-16 04:33:42 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// In place update is true by default if the MINIO_UPDATE is not set
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// or is not set to 'off', if MINIO_UPDATE is set to 'off' then
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// in-place update is off.
 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-05 07:32:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									globalInplaceUpdateDisabled  =  strings . EqualFold ( env . Get ( config . EnvUpdate ,  config . EnableOn ) ,  config . EnableOff ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-02 06:53:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-11-14 09:38:05 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  env . IsSet ( config . EnvAccessKey )  ||  env . IsSet ( config . EnvSecretKey )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										cred ,  err  :=  auth . CreateCredentials ( env . Get ( config . EnvAccessKey ,  "" ) ,  env . Get ( config . EnvSecretKey ,  "" ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-11-02 06:53:16 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( config . ErrInvalidCredentials ( err ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"Unable to validate credentials inherited from the shell environment" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalActiveCred  =  cred 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalConfigEncrypted  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-15 09:27:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-06 02:22:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  env . IsSet ( config . EnvRootUser )  ||  env . IsSet ( config . EnvRootPassword )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										cred ,  err  :=  auth . CreateCredentials ( env . Get ( config . EnvRootUser ,  "" ) ,  env . Get ( config . EnvRootPassword ,  "" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( config . ErrInvalidCredentials ( err ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"Unable to validate credentials inherited from the shell environment" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalActiveCred  =  cred 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalConfigEncrypted  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-03-18 01:36:13 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  env . IsSet ( config . EnvAccessKeyOld )  &&  env . IsSet ( config . EnvSecretKeyOld )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										oldCred ,  err  :=  auth . CreateCredentials ( env . Get ( config . EnvAccessKeyOld ,  "" ) ,  env . Get ( config . EnvSecretKeyOld ,  "" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( config . ErrInvalidCredentials ( err ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"Unable to validate the old credentials inherited from the shell environment" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalOldCred  =  oldCred 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Unsetenv ( config . EnvAccessKeyOld ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Unsetenv ( config . EnvSecretKeyOld ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-06 02:22:57 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  env . IsSet ( config . EnvRootUserOld )  &&  env . IsSet ( config . EnvRootPasswordOld )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										oldCred ,  err  :=  auth . CreateCredentials ( env . Get ( config . EnvRootUserOld ,  "" ) ,  env . Get ( config . EnvRootPasswordOld ,  "" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											logger . Fatal ( config . ErrInvalidCredentials ( err ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												"Unable to validate the old credentials inherited from the shell environment" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										globalOldCred  =  oldCred 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Unsetenv ( config . EnvRootUserOld ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Unsetenv ( config . EnvRootPasswordOld ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2017-06-10 10:50:51 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2019-09-22 16:24:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-16 09:35:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  logStartupMessage ( msg  string )  {  
						 
					
						
							
								
									
										
										
										
											2019-09-23 01:45:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  globalConsoleSys  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-12 09:50:54 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										globalConsoleSys . Send ( msg ,  string ( logger . All ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-09-23 01:45:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-16 09:35:41 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									logger . StartupMessage ( msg ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-09-22 16:24:32 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  getTLSConfig ( )  ( x509Certs  [ ] * x509 . Certificate ,  manager  * certs . Manager ,  secureConn  bool ,  err  error )  {  
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  ! ( isFile ( getPublicCertFile ( ) )  &&  isFile ( getPrivateKeyFile ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  nil ,  false ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  x509Certs ,  err  =  config . ParsePublicCertFile ( getPublicCertFile ( ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  nil ,  false ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									manager ,  err  =  certs . NewManager ( GlobalContext ,  getPublicCertFile ( ) ,  getPrivateKeyFile ( ) ,  config . LoadX509KeyPair ) 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  nil ,  false ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									// MinIO has support for multiple certificates. It expects the following structure:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//  certs/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   │
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   ├─ public.crt
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   ├─ private.key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   │
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   ├─ example.com/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   │   │
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   │   ├─ public.crt
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   │   └─ private.key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   └─ foobar.org/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//      │
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//      ├─ public.crt
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//      └─ private.key
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//   ...
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									//
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Therefore, we read all filenames in the cert directory and check
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// for each directory whether it contains a public.crt and private.key.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// If so, we try to add it to certificate manager.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									root ,  err  :=  os . Open ( globalCertsDir . Get ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  nil ,  false ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  root . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									files ,  err  :=  root . Readdir ( - 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  nil ,  false ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  file  :=  range  files  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-30 23:21:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										// Ignore all
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// - regular files
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// - "CAs" directory
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// - any directory which starts with ".."
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  file . Mode ( ) . IsRegular ( )  ||  file . Name ( )  ==  "CAs"  ||  strings . HasPrefix ( file . Name ( ) ,  ".." )  { 
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-30 23:21:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  file . Mode ( ) & os . ModeSymlink  ==  os . ModeSymlink  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											file ,  err  =  os . Stat ( filepath . Join ( root . Name ( ) ,  file . Name ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												// not accessible ignore
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  ! file . IsDir ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											certFile  =  filepath . Join ( root . Name ( ) ,  file . Name ( ) ,  publicCertFile ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											keyFile   =  filepath . Join ( root . Name ( ) ,  file . Name ( ) ,  privateKeyFile ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ! isFile ( certFile )  ||  ! isFile ( keyFile )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-09-30 23:21:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  =  manager . AddCertificate ( certFile ,  keyFile ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											err  =  fmt . Errorf ( "Unable to load TLS certificate '%s,%s': %w" ,  certFile ,  keyFile ,  err ) 
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											logger . LogIf ( GlobalContext ,  err ,  logger . Minio ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									secureConn  =  true 
							 
						 
					
						
							
								
									
										
											 
										
											
												certs: refactor cert manager to support multiple certificates (#10207)
This commit refactors the certificate management implementation
in the `certs` package such that multiple certificates can be
specified at the same time. Therefore, the following layout of
the `certs/` directory is expected:
```
certs/
 │
 ├─ public.crt
 ├─ private.key
 ├─ CAs/          // CAs directory is ignored
 │   │
 │    ...
 │
 ├─ example.com/
 │   │
 │   ├─ public.crt
 │   └─ private.key
 └─ foobar.org/
     │
     ├─ public.crt
     └─ private.key
   ...
```
However, directory names like `example.com` are just for human
readability/organization and don't have any meaning w.r.t whether
a particular certificate is served or not. This decision is made based
on the SNI sent by the client and the SAN of the certificate.
***
The `Manager` will pick a certificate based on the client trying
to establish a TLS connection. In particular, it looks at the client
hello (i.e. SNI) to determine which host the client tries to access.
If the manager can find a certificate that matches the SNI it
returns this certificate to the client.
However, the client may choose to not send an SNI or tries to access
a server directly via IP (`https://<ip>:<port>`). In this case, we
cannot use the SNI to determine which certificate to serve. However,
we also should not pick "the first" certificate that would be accepted
by the client (based on crypto. parameters - like a signature algorithm)
because it may be an internal certificate that contains internal hostnames. 
We would disclose internal infrastructure details doing so.
Therefore, the `Manager` returns the "default" certificate when the
client does not specify an SNI. The default certificate the top-level
`public.crt` - i.e. `certs/public.crt`.
This approach has some consequences:
 - It's the operator's responsibility to ensure that the top-level
   `public.crt` does not disclose any information (i.e. hostnames)
   that are not publicly visible. However, this was the case in the
   past already.
 - Any other `public.crt` - except for the top-level one - must not
   contain any IP SAN. The reason for this restriction is that the
   Manager cannot match a SNI to an IP b/c the SNI is the server host
   name. The entire purpose of SNI is to indicate which host the client
   tries to connect to when multiple hosts run on the same IP. So, a
   client will not set the SNI to an IP.
   If we would allow IP SANs in a lower-level `public.crt` a user would
   expect that it is possible to connect to MinIO directly via IP address
   and that the MinIO server would pick "the right" certificate. However,
   the MinIO server cannot determine which certificate to serve, and
   therefore always picks the "default" one. This may lead to all sorts
   of confusing errors like:
   "It works if I use `https:instance.minio.local` but not when I use
   `https://10.0.2.1`.
These consequences/limitations should be pointed out / explained in our
docs in an appropriate way. However, the support for multiple
certificates should not have any impact on how deployment with a single
certificate function today.
Co-authored-by: Harshavardhana <harsha@minio.io>
											 
										 
										
											2020-09-04 14:33:37 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									return  x509Certs ,  manager ,  secureConn ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-08 13:47:56 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
									
										
										
										
											2021-03-27 02:18:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// contextCanceled returns whether a context is canceled.
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  contextCanceled ( ctx  context . Context )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									select  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  <- ctx . Done ( ) : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}