github.com/hyperledger/fabric-ca@v2.0.0-alpha.0.20201120210307-7b4f34729db1+incompatible/cmd/fabric-ca-server/config.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package main
     8  
     9  import (
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"github.com/cloudflare/cfssl/log"
    16  	calog "github.com/hyperledger/fabric-ca/internal/pkg/log"
    17  	"github.com/hyperledger/fabric-ca/internal/pkg/util"
    18  	"github.com/hyperledger/fabric-ca/lib"
    19  	"github.com/hyperledger/fabric-ca/lib/metadata"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  const (
    24  	longName     = "Hyperledger Fabric Certificate Authority Server"
    25  	shortName    = "fabric-ca server"
    26  	cmdName      = "fabric-ca-server"
    27  	envVarPrefix = "FABRIC_CA_SERVER"
    28  	homeEnvVar   = "FABRIC_CA_SERVER_HOME"
    29  	caNameReqMsg = "ca.name property is required but is missing from the configuration file"
    30  )
    31  
    32  const (
    33  	defaultCfgTemplate = `#############################################################################
    34  #   This is a configuration file for the fabric-ca-server command.
    35  #
    36  #   COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES
    37  #   ------------------------------------------------
    38  #   Each configuration element can be overridden via command line
    39  #   arguments or environment variables.  The precedence for determining
    40  #   the value of each element is as follows:
    41  #   1) command line argument
    42  #      Examples:
    43  #      a) --port 443
    44  #         To set the listening port
    45  #      b) --ca.keyfile ../mykey.pem
    46  #         To set the "keyfile" element in the "ca" section below;
    47  #         note the '.' separator character.
    48  #   2) environment variable
    49  #      Examples:
    50  #      a) FABRIC_CA_SERVER_PORT=443
    51  #         To set the listening port
    52  #      b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem"
    53  #         To set the "keyfile" element in the "ca" section below;
    54  #         note the '_' separator character.
    55  #   3) configuration file
    56  #   4) default value (if there is one)
    57  #      All default values are shown beside each element below.
    58  #
    59  #   FILE NAME ELEMENTS
    60  #   ------------------
    61  #   The value of all fields whose name ends with "file" or "files" are
    62  #   name or names of other files.
    63  #   For example, see "tls.certfile" and "tls.clientauth.certfiles".
    64  #   The value of each of these fields can be a simple filename, a
    65  #   relative path, or an absolute path.  If the value is not an
    66  #   absolute path, it is interpretted as being relative to the location
    67  #   of this configuration file.
    68  #
    69  #############################################################################
    70  
    71  # Version of config file
    72  version: <<<VERSION>>>
    73  
    74  # Server's listening port (default: 7054)
    75  port: 7054
    76  
    77  # Cross-Origin Resource Sharing (CORS)
    78  cors:
    79      enabled: false
    80      origins:
    81        - "*"
    82  
    83  # Enables debug logging (default: false)
    84  debug: false
    85  
    86  # Size limit of an acceptable CRL in bytes (default: 512000)
    87  crlsizelimit: 512000
    88  
    89  #############################################################################
    90  #  TLS section for the server's listening port
    91  #
    92  #  The following types are supported for client authentication: NoClientCert,
    93  #  RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven,
    94  #  and RequireAndVerifyClientCert.
    95  #
    96  #  Certfiles is a list of root certificate authorities that the server uses
    97  #  when verifying client certificates.
    98  #############################################################################
    99  tls:
   100    # Enable TLS (default: false)
   101    enabled: false
   102    # TLS for the server's listening port
   103    certfile:
   104    keyfile:
   105    clientauth:
   106      type: noclientcert
   107      certfiles:
   108  
   109  #############################################################################
   110  #  The CA section contains information related to the Certificate Authority
   111  #  including the name of the CA, which should be unique for all members
   112  #  of a blockchain network.  It also includes the key and certificate files
   113  #  used when issuing enrollment certificates (ECerts).
   114  #  The chainfile (if it exists) contains the certificate chain which
   115  #  should be trusted for this CA, where the 1st in the chain is always the
   116  #  root CA certificate.
   117  #############################################################################
   118  ca:
   119    # Name of this CA
   120    name:
   121    # Key file (is only used to import a private key into BCCSP)
   122    keyfile:
   123    # Certificate file (default: ca-cert.pem)
   124    certfile:
   125    # Chain file
   126    chainfile:
   127  
   128  #############################################################################
   129  #  The gencrl REST endpoint is used to generate a CRL that contains revoked
   130  #  certificates. This section contains configuration options that are used
   131  #  during gencrl request processing.
   132  #############################################################################
   133  crl:
   134    # Specifies expiration for the generated CRL. The number of hours
   135    # specified by this property is added to the UTC time, the resulting time
   136    # is used to set the 'Next Update' date of the CRL.
   137    expiry: 24h
   138  
   139  #############################################################################
   140  #  The registry section controls how the fabric-ca-server does two things:
   141  #  1) authenticates enrollment requests which contain a username and password
   142  #     (also known as an enrollment ID and secret).
   143  #  2) once authenticated, retrieves the identity's attribute names and values.
   144  #     These attributes are useful for making access control decisions in
   145  #     chaincode.
   146  #  There are two main configuration options:
   147  #  1) The fabric-ca-server is the registry.
   148  #     This is true if "ldap.enabled" in the ldap section below is false.
   149  #  2) An LDAP server is the registry, in which case the fabric-ca-server
   150  #     calls the LDAP server to perform these tasks.
   151  #     This is true if "ldap.enabled" in the ldap section below is true,
   152  #     which means this "registry" section is ignored.
   153  #############################################################################
   154  registry:
   155    # Maximum number of times a password/secret can be reused for enrollment
   156    # (default: -1, which means there is no limit)
   157    maxenrollments: -1
   158  
   159    # Contains identity information which is used when LDAP is disabled
   160    identities:
   161       - name: <<<ADMIN>>>
   162         pass: <<<ADMINPW>>>
   163         type: client
   164         affiliation: ""
   165         attrs:
   166            hf.Registrar.Roles: "*"
   167            hf.Registrar.DelegateRoles: "*"
   168            hf.Revoker: true
   169            hf.IntermediateCA: true
   170            hf.GenCRL: true
   171            hf.Registrar.Attributes: "*"
   172            hf.AffiliationMgr: true
   173  
   174  #############################################################################
   175  #  Database section
   176  #  Supported types are: "sqlite3", "postgres", and "mysql".
   177  #  The datasource value depends on the type.
   178  #  If the type is "sqlite3", the datasource value is a file name to use
   179  #  as the database store.  Since "sqlite3" is an embedded database, it
   180  #  may not be used if you want to run the fabric-ca-server in a cluster.
   181  #  To run the fabric-ca-server in a cluster, you must choose "postgres"
   182  #  or "mysql".
   183  #############################################################################
   184  db:
   185    type: sqlite3
   186    datasource: fabric-ca-server.db
   187    tls:
   188        enabled: false
   189        certfiles:
   190        client:
   191          certfile:
   192          keyfile:
   193  
   194  #############################################################################
   195  #  LDAP section
   196  #  If LDAP is enabled, the fabric-ca-server calls LDAP to:
   197  #  1) authenticate enrollment ID and secret (i.e. username and password)
   198  #     for enrollment requests;
   199  #  2) To retrieve identity attributes
   200  #############################################################################
   201  ldap:
   202     # Enables or disables the LDAP client (default: false)
   203     # If this is set to true, the "registry" section is ignored.
   204     enabled: false
   205     # The URL of the LDAP server
   206     url: ldap://<adminDN>:<adminPassword>@<host>:<port>/<base>
   207     # TLS configuration for the client connection to the LDAP server
   208     tls:
   209        certfiles:
   210        client:
   211           certfile:
   212           keyfile:
   213     # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes
   214     attribute:
   215        # 'names' is an array of strings containing the LDAP attribute names which are
   216        # requested from the LDAP server for an LDAP identity's entry
   217        names: ['uid','member']
   218        # The 'converters' section is used to convert an LDAP entry to the value of
   219        # a fabric CA attribute.
   220        # For example, the following converts an LDAP 'uid' attribute
   221        # whose value begins with 'revoker' to a fabric CA attribute
   222        # named "hf.Revoker" with a value of "true" (because the boolean expression
   223        # evaluates to true).
   224        #    converters:
   225        #       - name: hf.Revoker
   226        #         value: attr("uid") =~ "revoker*"
   227        converters:
   228           - name:
   229             value:
   230        # The 'maps' section contains named maps which may be referenced by the 'map'
   231        # function in the 'converters' section to map LDAP responses to arbitrary values.
   232        # For example, assume a user has an LDAP attribute named 'member' which has multiple
   233        # values which are each a distinguished name (i.e. a DN). For simplicity, assume the
   234        # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'.
   235        # Further assume the following configuration.
   236        #    converters:
   237        #       - name: hf.Registrar.Roles
   238        #         value: map(attr("member"),"groups")
   239        #    maps:
   240        #       groups:
   241        #          - name: dn1
   242        #            value: peer
   243        #          - name: dn2
   244        #            value: client
   245        # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be
   246        # "peer,client,dn3".  This is because the value of 'attr("member")' is
   247        # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of
   248        # "group" replaces "dn1" with "peer" and "dn2" with "client".
   249        maps:
   250           groups:
   251              - name:
   252                value:
   253  
   254  #############################################################################
   255  # Affiliations section. Fabric CA server can be bootstrapped with the
   256  # affiliations specified in this section. Affiliations are specified as maps.
   257  # For example:
   258  #   businessunit1:
   259  #     department1:
   260  #       - team1
   261  #   businessunit2:
   262  #     - department2
   263  #     - department3
   264  #
   265  # Affiliations are hierarchical in nature. In the above example,
   266  # department1 (used as businessunit1.department1) is the child of businessunit1.
   267  # team1 (used as businessunit1.department1.team1) is the child of department1.
   268  # department2 (used as businessunit2.department2) and department3 (businessunit2.department3)
   269  # are children of businessunit2.
   270  # Note: Affiliations are case sensitive except for the non-leaf affiliations
   271  # (like businessunit1, department1, businessunit2) that are specified in the configuration file,
   272  # which are always stored in lower case.
   273  #############################################################################
   274  affiliations:
   275     org1:
   276        - department1
   277        - department2
   278     org2:
   279        - department1
   280  
   281  #############################################################################
   282  #  Signing section
   283  #
   284  #  The "default" subsection is used to sign enrollment certificates;
   285  #  the default expiration ("expiry" field) is "8760h", which is 1 year in hours.
   286  #
   287  #  The "ca" profile subsection is used to sign intermediate CA certificates;
   288  #  the default expiration ("expiry" field) is "43800h" which is 5 years in hours.
   289  #  Note that "isca" is true, meaning that it issues a CA certificate.
   290  #  A maxpathlen of 0 means that the intermediate CA cannot issue other
   291  #  intermediate CA certificates, though it can still issue end entity certificates.
   292  #  (See RFC 5280, section 4.2.1.9)
   293  #
   294  #  The "tls" profile subsection is used to sign TLS certificate requests;
   295  #  the default expiration ("expiry" field) is "8760h", which is 1 year in hours.
   296  #############################################################################
   297  signing:
   298      default:
   299        usage:
   300          - digital signature
   301        expiry: 8760h
   302      profiles:
   303        ca:
   304           usage:
   305             - cert sign
   306             - crl sign
   307           expiry: 43800h
   308           caconstraint:
   309             isca: true
   310             maxpathlen: 0
   311        tls:
   312           usage:
   313              - signing
   314              - key encipherment
   315              - server auth
   316              - client auth
   317              - key agreement
   318           expiry: 8760h
   319  
   320  ###########################################################################
   321  #  Certificate Signing Request (CSR) section.
   322  #  This controls the creation of the root CA certificate.
   323  #  The expiration for the root CA certificate is configured with the
   324  #  "ca.expiry" field below, whose default value is "131400h" which is
   325  #  15 years in hours.
   326  #  The pathlength field is used to limit CA certificate hierarchy as described
   327  #  in section 4.2.1.9 of RFC 5280.
   328  #  Examples:
   329  #  1) No pathlength value means no limit is requested.
   330  #  2) pathlength == 1 means a limit of 1 is requested which is the default for
   331  #     a root CA.  This means the root CA can issue intermediate CA certificates,
   332  #     but these intermediate CAs may not in turn issue other CA certificates
   333  #     though they can still issue end entity certificates.
   334  #  3) pathlength == 0 means a limit of 0 is requested;
   335  #     this is the default for an intermediate CA, which means it can not issue
   336  #     CA certificates though it can still issue end entity certificates.
   337  ###########################################################################
   338  csr:
   339     cn: <<<COMMONNAME>>>
   340     keyrequest:
   341       algo: ecdsa
   342       size: 256
   343     names:
   344        - C: US
   345          ST: "North Carolina"
   346          L:
   347          O: Hyperledger
   348          OU: Fabric
   349     hosts:
   350       - <<<MYHOST>>>
   351       - localhost
   352     ca:
   353        expiry: 131400h
   354        pathlength: <<<PATHLENGTH>>>
   355  
   356  ###########################################################################
   357  # Each CA can issue both X509 enrollment certificate as well as Idemix
   358  # Credential. This section specifies configuration for the issuer component
   359  # that is responsible for issuing Idemix credentials.
   360  ###########################################################################
   361  idemix:
   362    # Specifies pool size for revocation handles. A revocation handle is an unique identifier of an
   363    # Idemix credential. The issuer will create a pool revocation handles of this specified size. When
   364    # a credential is requested, issuer will get handle from the pool and assign it to the credential.
   365    # Issuer will repopulate the pool with new handles when the last handle in the pool is used.
   366    # A revocation handle and credential revocation information (CRI) are used to create non revocation proof
   367    # by the prover to prove to the verifier that her credential is not revoked.
   368    rhpoolsize: 1000
   369  
   370    # The Idemix credential issuance is a two step process. First step is to  get a nonce from the issuer
   371    # and second step is send credential request that is constructed using the nonce to the isuser to
   372    # request a credential. This configuration property specifies expiration for the nonces. By default is
   373    # nonces expire after 15 seconds. The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration).
   374    nonceexpiration: 15s
   375  
   376    # Specifies interval at which expired nonces are removed from datastore. Default value is 15 minutes.
   377    #  The value is expressed in the time.Duration format (see https://golang.org/pkg/time/#ParseDuration)
   378    noncesweepinterval: 15m
   379  
   380  #############################################################################
   381  # BCCSP (BlockChain Crypto Service Provider) section is used to select which
   382  # crypto library implementation to use
   383  #############################################################################
   384  bccsp:
   385      default: SW
   386      sw:
   387          hash: SHA2
   388          security: 256
   389          filekeystore:
   390              # The directory used for the software file-based keystore
   391              keystore: msp/keystore
   392  
   393  #############################################################################
   394  # Multi CA section
   395  #
   396  # Each Fabric CA server contains one CA by default.  This section is used
   397  # to configure multiple CAs in a single server.
   398  #
   399  # 1) --cacount <number-of-CAs>
   400  # Automatically generate <number-of-CAs> non-default CAs.  The names of these
   401  # additional CAs are "ca1", "ca2", ... "caN", where "N" is <number-of-CAs>
   402  # This is particularly useful in a development environment to quickly set up
   403  # multiple CAs. Note that, this config option is not applicable to intermediate CA server
   404  # i.e., Fabric CA server that is started with intermediate.parentserver.url config
   405  # option (-u command line option)
   406  #
   407  # 2) --cafiles <CA-config-files>
   408  # For each CA config file in the list, generate a separate signing CA.  Each CA
   409  # config file in this list MAY contain all of the same elements as are found in
   410  # the server config file except port, debug, and tls sections.
   411  #
   412  # Examples:
   413  # fabric-ca-server start -b admin:adminpw --cacount 2
   414  #
   415  # fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml
   416  # --cafiles ca/ca2/fabric-ca-server-config.yaml
   417  #
   418  #############################################################################
   419  
   420  cacount:
   421  
   422  cafiles:
   423  
   424  #############################################################################
   425  # Intermediate CA section
   426  #
   427  # The relationship between servers and CAs is as follows:
   428  #   1) A single server process may contain or function as one or more CAs.
   429  #      This is configured by the "Multi CA section" above.
   430  #   2) Each CA is either a root CA or an intermediate CA.
   431  #   3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA.
   432  #
   433  # This section pertains to configuration of #2 and #3.
   434  # If the "intermediate.parentserver.url" property is set,
   435  # then this is an intermediate CA with the specified parent
   436  # CA.
   437  #
   438  # parentserver section
   439  #    url - The URL of the parent server
   440  #    caname - Name of the CA to enroll within the server
   441  #
   442  # enrollment section used to enroll intermediate CA with parent CA
   443  #    profile - Name of the signing profile to use in issuing the certificate
   444  #    label - Label to use in HSM operations
   445  #
   446  # tls section for secure socket connection
   447  #   certfiles - PEM-encoded list of trusted root certificate files
   448  #   client:
   449  #     certfile - PEM-encoded certificate file for when client authentication
   450  #     is enabled on server
   451  #     keyfile - PEM-encoded key file for when client authentication
   452  #     is enabled on server
   453  #############################################################################
   454  intermediate:
   455    parentserver:
   456      url:
   457      caname:
   458  
   459    enrollment:
   460      hosts:
   461      profile:
   462      label:
   463  
   464    tls:
   465      certfiles:
   466      client:
   467        certfile:
   468        keyfile:
   469  
   470  #############################################################################
   471  # CA configuration section
   472  #
   473  # Configure the number of incorrect password attempts are allowed for
   474  # identities. By default, the value of 'passwordattempts' is 10, which
   475  # means that 10 incorrect password attempts can be made before an identity get
   476  # locked out.
   477  #############################################################################
   478  cfg:
   479    identities:
   480      passwordattempts: 10
   481  
   482  ###############################################################################
   483  #
   484  #    Operations section
   485  #
   486  ###############################################################################
   487  operations:
   488      # host and port for the operations server
   489      listenAddress: 127.0.0.1:9443
   490  
   491      # TLS configuration for the operations endpoint
   492      tls:
   493          # TLS enabled
   494          enabled: false
   495  
   496          # path to PEM encoded server certificate for the operations server
   497          cert:
   498              file:
   499  
   500          # path to PEM encoded server key for the operations server
   501          key:
   502              file:
   503  
   504          # require client certificate authentication to access all resources
   505          clientAuthRequired: false
   506  
   507          # paths to PEM encoded ca certificates to trust for client authentication
   508          clientRootCAs:
   509              files: []
   510  
   511  ###############################################################################
   512  #
   513  #    Metrics section
   514  #
   515  ###############################################################################
   516  metrics:
   517      # statsd, prometheus, or disabled
   518      provider: disabled
   519  
   520      # statsd configuration
   521      statsd:
   522          # network type: tcp or udp
   523          network: udp
   524  
   525          # statsd server address
   526          address: 127.0.0.1:8125
   527  
   528          # the interval at which locally cached counters and gauges are pushsed
   529          # to statsd; timings are pushed immediately
   530          writeInterval: 10s
   531  
   532          # prefix is prepended to all emitted statsd merics
   533          prefix: server
   534  `
   535  )
   536  
   537  var (
   538  	extraArgsError = "Unrecognized arguments found: %v\n\n%s"
   539  )
   540  
   541  // Initialize config
   542  func (s *ServerCmd) configInit() (err error) {
   543  	if !s.configRequired() {
   544  		return nil
   545  	}
   546  
   547  	s.cfgFileName, s.homeDirectory, err = util.ValidateAndReturnAbsConf(s.cfgFileName, s.homeDirectory, cmdName)
   548  	if err != nil {
   549  		return err
   550  	}
   551  
   552  	s.myViper.AutomaticEnv() // read in environment variables that match
   553  	logLevel := s.myViper.GetString("loglevel")
   554  	debug := s.myViper.GetBool("debug")
   555  	calog.SetLogLevel(logLevel, debug)
   556  
   557  	log.Debugf("Home directory: %s", s.homeDirectory)
   558  
   559  	// If the config file doesn't exist, create a default one
   560  	if !util.FileExists(s.cfgFileName) {
   561  		err = s.createDefaultConfigFile()
   562  		if err != nil {
   563  			return errors.WithMessage(err, "Failed to create default configuration file")
   564  		}
   565  		log.Infof("Created default configuration file at %s", s.cfgFileName)
   566  	} else {
   567  		log.Infof("Configuration file location: %s", s.cfgFileName)
   568  	}
   569  
   570  	// Read the config
   571  	err = lib.UnmarshalConfig(s.cfg, s.myViper, s.cfgFileName, true)
   572  	if err != nil {
   573  		return err
   574  	}
   575  
   576  	// Read operations tls files
   577  	if s.myViper.GetBool("operations.tls.enabled") {
   578  		cf := s.myViper.GetString("operations.tls.cert.file")
   579  		if cf == "" {
   580  			cf = s.cfg.Operations.TLS.CertFile
   581  		}
   582  		if !filepath.IsAbs(cf) {
   583  			cf = filepath.Join(s.homeDirectory, cf)
   584  		}
   585  		if !util.FileExists(cf) {
   586  			return errors.Errorf("failed to read certificate file: %s", cf)
   587  		}
   588  		s.cfg.Operations.TLS.CertFile = cf
   589  
   590  		kf := s.myViper.GetString("operations.tls.key.file")
   591  		if kf == "" {
   592  			kf = s.cfg.Operations.TLS.KeyFile
   593  		}
   594  		if !filepath.IsAbs(kf) {
   595  			kf = filepath.Join(s.homeDirectory, kf)
   596  		}
   597  		if !util.FileExists(kf) {
   598  			return errors.Errorf("failed to read key file: %s", kf)
   599  		}
   600  		s.cfg.Operations.TLS.KeyFile = kf
   601  	}
   602  
   603  	// The pathlength field controls how deep the CA hierarchy when requesting
   604  	// certificates. If it is explicitly set to 0, set the PathLenZero field to
   605  	// true as CFSSL expects.
   606  	pl := "csr.ca.pathlength"
   607  	if s.myViper.IsSet(pl) && s.myViper.GetInt(pl) == 0 {
   608  		s.cfg.CAcfg.CSR.CA.PathLenZero = true
   609  	}
   610  	// The maxpathlen field controls how deep the CA hierarchy when issuing
   611  	// a CA certificate. If it is explicitly set to 0, set the PathLenZero
   612  	// field to true as CFSSL expects.
   613  	pl = "signing.profiles.ca.caconstraint.maxpathlen"
   614  	if s.myViper.IsSet(pl) && s.myViper.GetInt(pl) == 0 {
   615  		s.cfg.CAcfg.Signing.Profiles["ca"].CAConstraint.MaxPathLenZero = true
   616  	}
   617  
   618  	return nil
   619  }
   620  
   621  func (s *ServerCmd) createDefaultConfigFile() error {
   622  	var user, pass string
   623  	// If LDAP is enabled, authentication of enrollment requests are performed
   624  	// by using LDAP authentication; therefore, no bootstrap username and password
   625  	// are required.
   626  	ldapEnabled := s.myViper.GetBool("ldap.enabled")
   627  	if !ldapEnabled {
   628  		// When LDAP is disabled, the fabric-ca-server functions as its own
   629  		// identity registry; therefore, we require that the default configuration
   630  		// file have a bootstrap username and password that is used to enroll a
   631  		// bootstrap administrator.  Other identities can be dynamically registered.
   632  		// Create the default config, but only if they provided this bootstrap
   633  		// username and password.
   634  		up := s.myViper.GetString("boot")
   635  		if up == "" {
   636  			return errors.New("The '-b user:pass' option is required")
   637  		}
   638  		ups := strings.Split(up, ":")
   639  		if len(ups) < 2 {
   640  			return errors.Errorf("The value '%s' on the command line is missing a colon separator", up)
   641  		}
   642  		if len(ups) > 2 {
   643  			ups = []string{ups[0], strings.Join(ups[1:], ":")}
   644  		}
   645  		user = ups[0]
   646  		pass = ups[1]
   647  		if len(user) >= 1024 {
   648  			return errors.Errorf("The identity name must be less than 1024 characters: '%s'", user)
   649  		}
   650  		if len(pass) == 0 {
   651  			return errors.New("An empty password in the '-b user:pass' option is not permitted")
   652  		}
   653  	}
   654  
   655  	var myhost string
   656  	var err error
   657  	myhost, err = os.Hostname()
   658  	if err != nil {
   659  		return err
   660  	}
   661  
   662  	// Do string subtitution to get the default config
   663  	cfg := strings.Replace(defaultCfgTemplate, "<<<VERSION>>>", metadata.Version, 1)
   664  	cfg = strings.Replace(cfg, "<<<ADMIN>>>", user, 1)
   665  	cfg = strings.Replace(cfg, "<<<ADMINPW>>>", pass, 1)
   666  	cfg = strings.Replace(cfg, "<<<MYHOST>>>", myhost, 1)
   667  	purl := s.myViper.GetString("intermediate.parentserver.url")
   668  	log.Debugf("parent server URL: '%s'", util.GetMaskedURL(purl))
   669  	if purl == "" {
   670  		// This is a root CA
   671  		cfg = strings.Replace(cfg, "<<<COMMONNAME>>>", "fabric-ca-server", 1)
   672  		cfg = strings.Replace(cfg, "<<<PATHLENGTH>>>", "1", 1)
   673  	} else {
   674  		// This is an intermediate CA
   675  		cfg = strings.Replace(cfg, "<<<COMMONNAME>>>", "", 1)
   676  		cfg = strings.Replace(cfg, "<<<PATHLENGTH>>>", "0", 1)
   677  	}
   678  
   679  	// Now write the file
   680  	cfgDir := filepath.Dir(s.cfgFileName)
   681  	err = os.MkdirAll(cfgDir, 0755)
   682  	if err != nil {
   683  		return err
   684  	}
   685  
   686  	// Now write the file
   687  	return ioutil.WriteFile(s.cfgFileName, []byte(cfg), 0644)
   688  }