github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/common/tools/cryptogen/main.go (about)

     1  /*
     2  Copyright IBM Corp. 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  package main
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"path/filepath"
    23  	"text/template"
    24  
    25  	"gopkg.in/yaml.v2"
    26  
    27  	"gopkg.in/alecthomas/kingpin.v2"
    28  
    29  	"bytes"
    30  	"io/ioutil"
    31  
    32  	"github.com/hyperledger/fabric/common/tools/cryptogen/ca"
    33  	"github.com/hyperledger/fabric/common/tools/cryptogen/metadata"
    34  	"github.com/hyperledger/fabric/common/tools/cryptogen/msp"
    35  )
    36  
    37  const (
    38  	userBaseName            = "User"
    39  	adminBaseName           = "Admin"
    40  	defaultHostnameTemplate = "{{.Prefix}}{{.Index}}"
    41  	defaultCNTemplate       = "{{.Hostname}}.{{.Domain}}"
    42  )
    43  
    44  type HostnameData struct {
    45  	Prefix string
    46  	Index  int
    47  	Domain string
    48  }
    49  
    50  type SpecData struct {
    51  	Hostname   string
    52  	Domain     string
    53  	CommonName string
    54  }
    55  
    56  type NodeTemplate struct {
    57  	Count    int      `yaml:"Count"`
    58  	Start    int      `yaml:"Start"`
    59  	Hostname string   `yaml:"Hostname"`
    60  	SANS     []string `yaml:"SANS"`
    61  }
    62  
    63  type NodeSpec struct {
    64  	Hostname   string   `yaml:"Hostname"`
    65  	CommonName string   `yaml:"CommonName"`
    66  	SANS       []string `yaml:"SANS"`
    67  }
    68  
    69  type UsersSpec struct {
    70  	Count int `yaml:"Count"`
    71  }
    72  
    73  type OrgSpec struct {
    74  	Name     string       `yaml:"Name"`
    75  	Domain   string       `yaml:"Domain"`
    76  	CA       NodeSpec     `yaml:"CA"`
    77  	Template NodeTemplate `yaml:"Template"`
    78  	Specs    []NodeSpec   `yaml:"Specs"`
    79  	Users    UsersSpec    `yaml:"Users"`
    80  }
    81  
    82  type Config struct {
    83  	OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"`
    84  	PeerOrgs    []OrgSpec `yaml:"PeerOrgs"`
    85  }
    86  
    87  var defaultConfig = `
    88  # ---------------------------------------------------------------------------
    89  # "OrdererOrgs" - Definition of organizations managing orderer nodes
    90  # ---------------------------------------------------------------------------
    91  OrdererOrgs:
    92    # ---------------------------------------------------------------------------
    93    # Orderer
    94    # ---------------------------------------------------------------------------
    95    - Name: Orderer
    96      Domain: example.com
    97  
    98      # ---------------------------------------------------------------------------
    99      # "Specs" - See PeerOrgs below for complete description
   100      # ---------------------------------------------------------------------------
   101      Specs:
   102        - Hostname: orderer
   103  
   104  # ---------------------------------------------------------------------------
   105  # "PeerOrgs" - Definition of organizations managing peer nodes
   106  # ---------------------------------------------------------------------------
   107  PeerOrgs:
   108    # ---------------------------------------------------------------------------
   109    # Org1
   110    # ---------------------------------------------------------------------------
   111    - Name: Org1
   112      Domain: org1.example.com
   113  
   114      # ---------------------------------------------------------------------------
   115      # "CA"
   116      # ---------------------------------------------------------------------------
   117      # Uncomment this section to enable the explicit definition of the CA for this
   118      # organization.  This entry is a Spec.  See "Specs" section below for details.
   119      # ---------------------------------------------------------------------------
   120      # CA:
   121      #    Hostname: ca # implicitly ca.org1.example.com
   122  
   123      # ---------------------------------------------------------------------------
   124      # "Specs"
   125      # ---------------------------------------------------------------------------
   126      # Uncomment this section to enable the explicit definition of hosts in your
   127      # configuration.  Most users will want to use Template, below
   128      #
   129      # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
   130      #   - Hostname:   (Required) The desired hostname, sans the domain.
   131      #   - CommonName: (Optional) Specifies the template or explicit override for
   132      #                 the CN.  By default, this is the template:
   133      #
   134      #                              "{{.Hostname}}.{{.Domain}}"
   135      #
   136      #                 which obtains its values from the Spec.Hostname and
   137      #                 Org.Domain, respectively.
   138      #   - SANS:       (Optional) Specifies one or more Subject Alternative Names
   139      #                 the be set in the resulting x509.  Accepts template
   140      #                 variables {{.Hostname}}, {{.Domain}}, {{.CommonName}}
   141      #                 NOTE: Two implicit entries are created for you:
   142      #                     - {{ .CommonName }}
   143      #                     - {{ .Hostname }}
   144      # ---------------------------------------------------------------------------
   145      # Specs:
   146      #   - Hostname: foo # implicitly "foo.org1.example.com"
   147      #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
   148      #     SANS:
   149      #       - "bar.{{.Domain}}"
   150      #       - "altfoo.{{.Domain}}"
   151      #       - "{{.Hostname}}.org6.net"
   152      #   - Hostname: bar
   153      #   - Hostname: baz
   154  
   155      # ---------------------------------------------------------------------------
   156      # "Template"
   157      # ---------------------------------------------------------------------------
   158      # Allows for the definition of 1 or more hosts that are created sequentially
   159      # from a template. By default, this looks like "peer%d" from 0 to Count-1.
   160      # You may override the number of nodes (Count), the starting index (Start)
   161      # or the template used to construct the name (Hostname).
   162      #
   163      # Note: Template and Specs are not mutually exclusive.  You may define both
   164      # sections and the aggregate nodes will be created for you.  Take care with
   165      # name collisions
   166      # ---------------------------------------------------------------------------
   167      Template:
   168        Count: 1
   169        # Start: 5
   170        # Hostname: {{.Prefix}}{{.Index}} # default
   171        # SANS:
   172        #   - "{{.Hostname}}.alt.{{.Domain}}"
   173  
   174      # ---------------------------------------------------------------------------
   175      # "Users"
   176      # ---------------------------------------------------------------------------
   177      # Count: The number of user accounts _in addition_ to Admin
   178      # ---------------------------------------------------------------------------
   179      Users:
   180        Count: 1
   181  
   182    # ---------------------------------------------------------------------------
   183    # Org2: See "Org1" for full specification
   184    # ---------------------------------------------------------------------------
   185    - Name: Org2
   186      Domain: org2.example.com
   187      Template:
   188        Count: 1
   189      Users:
   190        Count: 1
   191  `
   192  
   193  //command line flags
   194  var (
   195  	app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material")
   196  
   197  	gen        = app.Command("generate", "Generate key material")
   198  	outputDir  = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String()
   199  	configFile = gen.Flag("config", "The configuration template to use").File()
   200  
   201  	showtemplate = app.Command("showtemplate", "Show the default configuration template")
   202  
   203  	version = app.Command("version", "Show version information")
   204  )
   205  
   206  func main() {
   207  	kingpin.Version("0.0.1")
   208  	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
   209  
   210  	// "generate" command
   211  	case gen.FullCommand():
   212  		generate()
   213  
   214  	// "showtemplate" command
   215  	case showtemplate.FullCommand():
   216  		fmt.Print(defaultConfig)
   217  		os.Exit(0)
   218  
   219  	// "version" command
   220  	case version.FullCommand():
   221  		printVersion()
   222  	}
   223  
   224  }
   225  
   226  func getConfig() (*Config, error) {
   227  	var configData string
   228  
   229  	if *configFile != nil {
   230  		data, err := ioutil.ReadAll(*configFile)
   231  		if err != nil {
   232  			return nil, fmt.Errorf("Error reading configuration: %s", err)
   233  		}
   234  
   235  		configData = string(data)
   236  	} else {
   237  		configData = defaultConfig
   238  	}
   239  
   240  	config := &Config{}
   241  	err := yaml.Unmarshal([]byte(configData), &config)
   242  	if err != nil {
   243  		return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err)
   244  	}
   245  
   246  	return config, nil
   247  }
   248  
   249  func generate() {
   250  
   251  	config, err := getConfig()
   252  	if err != nil {
   253  		fmt.Printf("Error reading config: %s", err)
   254  		os.Exit(-1)
   255  	}
   256  
   257  	for _, orgSpec := range config.PeerOrgs {
   258  		err = renderOrgSpec(&orgSpec, "peer")
   259  		if err != nil {
   260  			fmt.Printf("Error processing peer configuration: %s", err)
   261  			os.Exit(-1)
   262  		}
   263  		generatePeerOrg(*outputDir, orgSpec)
   264  	}
   265  
   266  	for _, orgSpec := range config.OrdererOrgs {
   267  		renderOrgSpec(&orgSpec, "orderer")
   268  		if err != nil {
   269  			fmt.Printf("Error processing orderer configuration: %s", err)
   270  			os.Exit(-1)
   271  		}
   272  		generateOrdererOrg(*outputDir, orgSpec)
   273  	}
   274  }
   275  
   276  func parseTemplate(input string, data interface{}) (string, error) {
   277  
   278  	t, err := template.New("parse").Parse(input)
   279  	if err != nil {
   280  		return "", fmt.Errorf("Error parsing template: %s", err)
   281  	}
   282  
   283  	output := new(bytes.Buffer)
   284  	err = t.Execute(output, data)
   285  	if err != nil {
   286  		return "", fmt.Errorf("Error executing template: %s", err)
   287  	}
   288  
   289  	return output.String(), nil
   290  }
   291  
   292  func parseTemplateWithDefault(input, defaultInput string, data interface{}) (string, error) {
   293  
   294  	// Use the default if the input is an empty string
   295  	if len(input) == 0 {
   296  		input = defaultInput
   297  	}
   298  
   299  	return parseTemplate(input, data)
   300  }
   301  
   302  func renderNodeSpec(domain string, spec *NodeSpec) error {
   303  	data := SpecData{
   304  		Hostname: spec.Hostname,
   305  		Domain:   domain,
   306  	}
   307  
   308  	// Process our CommonName
   309  	cn, err := parseTemplateWithDefault(spec.CommonName, defaultCNTemplate, data)
   310  	if err != nil {
   311  		return err
   312  	}
   313  
   314  	spec.CommonName = cn
   315  	data.CommonName = cn
   316  
   317  	// Save off our original, unprocessed SANS entries
   318  	origSANS := spec.SANS
   319  
   320  	// Set our implicit SANS entries for CN/Hostname
   321  	spec.SANS = []string{cn, spec.Hostname}
   322  
   323  	// Finally, process any remaining SANS entries
   324  	for _, _san := range origSANS {
   325  		san, err := parseTemplate(_san, data)
   326  		if err != nil {
   327  			return err
   328  		}
   329  
   330  		spec.SANS = append(spec.SANS, san)
   331  	}
   332  
   333  	return nil
   334  }
   335  
   336  func renderOrgSpec(orgSpec *OrgSpec, prefix string) error {
   337  	// First process all of our templated nodes
   338  	for i := 0; i < orgSpec.Template.Count; i++ {
   339  		data := HostnameData{
   340  			Prefix: prefix,
   341  			Index:  i + orgSpec.Template.Start,
   342  			Domain: orgSpec.Domain,
   343  		}
   344  
   345  		hostname, err := parseTemplateWithDefault(orgSpec.Template.Hostname, defaultHostnameTemplate, data)
   346  		if err != nil {
   347  			return err
   348  		}
   349  
   350  		spec := NodeSpec{
   351  			Hostname: hostname,
   352  			SANS:     orgSpec.Template.SANS,
   353  		}
   354  		orgSpec.Specs = append(orgSpec.Specs, spec)
   355  	}
   356  
   357  	// Touch up all general node-specs to add the domain
   358  	for idx, spec := range orgSpec.Specs {
   359  		err := renderNodeSpec(orgSpec.Domain, &spec)
   360  		if err != nil {
   361  			return err
   362  		}
   363  
   364  		orgSpec.Specs[idx] = spec
   365  	}
   366  
   367  	// Process the CA node-spec in the same manner
   368  	if len(orgSpec.CA.Hostname) == 0 {
   369  		orgSpec.CA.Hostname = "ca"
   370  	}
   371  	err := renderNodeSpec(orgSpec.Domain, &orgSpec.CA)
   372  	if err != nil {
   373  		return err
   374  	}
   375  
   376  	return nil
   377  }
   378  
   379  func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
   380  
   381  	orgName := orgSpec.Domain
   382  
   383  	fmt.Println(orgName)
   384  	// generate CAs
   385  	orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
   386  	caDir := filepath.Join(orgDir, "ca")
   387  	tlsCADir := filepath.Join(orgDir, "tlsca")
   388  	mspDir := filepath.Join(orgDir, "msp")
   389  	peersDir := filepath.Join(orgDir, "peers")
   390  	usersDir := filepath.Join(orgDir, "users")
   391  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   392  	// generate signing CA
   393  	signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
   394  	if err != nil {
   395  		fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
   396  		os.Exit(1)
   397  	}
   398  	// generate TLS CA
   399  	tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName)
   400  	if err != nil {
   401  		fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
   402  		os.Exit(1)
   403  	}
   404  
   405  	err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA)
   406  	if err != nil {
   407  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   408  		os.Exit(1)
   409  	}
   410  
   411  	generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA)
   412  
   413  	// TODO: add ability to specify usernames
   414  	users := []NodeSpec{}
   415  	for j := 1; j <= orgSpec.Users.Count; j++ {
   416  		user := NodeSpec{
   417  			CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
   418  		}
   419  
   420  		users = append(users, user)
   421  	}
   422  	// add an admin user
   423  	adminUser := NodeSpec{
   424  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   425  	}
   426  
   427  	users = append(users, adminUser)
   428  	generateNodes(usersDir, users, signCA, tlsCA)
   429  
   430  	// copy the admin cert to the org's MSP admincerts
   431  	err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
   432  	if err != nil {
   433  		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   434  			orgName, err)
   435  		os.Exit(1)
   436  	}
   437  
   438  	// copy the admin cert to each of the org's peer's MSP admincerts
   439  	for _, spec := range orgSpec.Specs {
   440  		err = copyAdminCert(usersDir,
   441  			filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   442  		if err != nil {
   443  			fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
   444  				orgName, spec.CommonName, err)
   445  			os.Exit(1)
   446  		}
   447  	}
   448  }
   449  
   450  func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
   451  	// delete the contents of admincerts
   452  	err := os.RemoveAll(adminCertsDir)
   453  	if err != nil {
   454  		return err
   455  	}
   456  	// recreate the admincerts directory
   457  	err = os.MkdirAll(adminCertsDir, 0755)
   458  	if err != nil {
   459  		return err
   460  	}
   461  	err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts",
   462  		adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
   463  		adminUserName+"-cert.pem"))
   464  	if err != nil {
   465  		return err
   466  	}
   467  	return nil
   468  
   469  }
   470  
   471  func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA) {
   472  
   473  	for _, node := range nodes {
   474  		nodeDir := filepath.Join(baseDir, node.CommonName)
   475  		err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA)
   476  		if err != nil {
   477  			fmt.Printf("Error generating local MSP for %s:\n%v\n", node, err)
   478  			os.Exit(1)
   479  		}
   480  	}
   481  }
   482  
   483  func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {
   484  
   485  	orgName := orgSpec.Domain
   486  
   487  	// generate CAs
   488  	orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
   489  	caDir := filepath.Join(orgDir, "ca")
   490  	tlsCADir := filepath.Join(orgDir, "tlsca")
   491  	mspDir := filepath.Join(orgDir, "msp")
   492  	orderersDir := filepath.Join(orgDir, "orderers")
   493  	usersDir := filepath.Join(orgDir, "users")
   494  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   495  	// generate signing CA
   496  	signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName)
   497  	if err != nil {
   498  		fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
   499  		os.Exit(1)
   500  	}
   501  	// generate TLS CA
   502  	tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName)
   503  	if err != nil {
   504  		fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
   505  		os.Exit(1)
   506  	}
   507  
   508  	err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA)
   509  	if err != nil {
   510  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   511  		os.Exit(1)
   512  	}
   513  
   514  	generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA)
   515  
   516  	adminUser := NodeSpec{
   517  		CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   518  	}
   519  
   520  	// generate an admin for the orderer org
   521  	users := []NodeSpec{}
   522  	// add an admin user
   523  	users = append(users, adminUser)
   524  	generateNodes(usersDir, users, signCA, tlsCA)
   525  
   526  	// copy the admin cert to the org's MSP admincerts
   527  	err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)
   528  	if err != nil {
   529  		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   530  			orgName, err)
   531  		os.Exit(1)
   532  	}
   533  
   534  	// copy the admin cert to each of the org's orderers's MSP admincerts
   535  	for _, spec := range orgSpec.Specs {
   536  		err = copyAdminCert(usersDir,
   537  			filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
   538  		if err != nil {
   539  			fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
   540  				orgName, spec.CommonName, err)
   541  			os.Exit(1)
   542  		}
   543  	}
   544  
   545  }
   546  
   547  func copyFile(src, dst string) error {
   548  	in, err := os.Open(src)
   549  	if err != nil {
   550  		return err
   551  	}
   552  	defer in.Close()
   553  	out, err := os.Create(dst)
   554  	if err != nil {
   555  		return err
   556  	}
   557  	defer out.Close()
   558  	_, err = io.Copy(out, in)
   559  	cerr := out.Close()
   560  	if err != nil {
   561  		return err
   562  	}
   563  	return cerr
   564  }
   565  
   566  func printVersion() {
   567  	fmt.Println(metadata.GetVersionInfo())
   568  }