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