github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/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/msp"
    34  )
    35  
    36  const (
    37  	userBaseName            = "User"
    38  	adminBaseName           = "Admin"
    39  	defaultHostnameTemplate = "{{.Prefix}}{{.Index}}"
    40  	defaultCNTemplate       = "{{.Hostname}}.{{.Domain}}"
    41  )
    42  
    43  type HostnameData struct {
    44  	Prefix string
    45  	Index  int
    46  	Domain string
    47  }
    48  
    49  type CommonNameData struct {
    50  	Hostname string
    51  	Domain   string
    52  }
    53  
    54  type NodeTemplate struct {
    55  	Count    int    `yaml:"Count"`
    56  	Start    int    `yaml:"Start"`
    57  	Hostname string `yaml:"Hostname"`
    58  }
    59  
    60  type NodeSpec struct {
    61  	Hostname     string   `yaml:"Hostname"`
    62  	AltHostnames []string `yaml:"AltHostnames"`
    63  	CommonName   string   `yaml:"CommonName"`
    64  }
    65  
    66  type UsersSpec struct {
    67  	Count int `yaml:"Count"`
    68  }
    69  
    70  type OrgSpec struct {
    71  	Name     string       `yaml:"Name"`
    72  	Domain   string       `yaml:"Domain"`
    73  	Template NodeTemplate `yaml:"Template"`
    74  	Specs    []NodeSpec   `yaml:"Specs"`
    75  	Users    UsersSpec    `yaml:"Users"`
    76  }
    77  
    78  type Config struct {
    79  	OrdererOrgs []OrgSpec `yaml:"OrdererOrgs"`
    80  	PeerOrgs    []OrgSpec `yaml:"PeerOrgs"`
    81  }
    82  
    83  var defaultConfig = `
    84  # ---------------------------------------------------------------------------
    85  # "OrdererOrgs" - Definition of organizations managing orderer nodes
    86  # ---------------------------------------------------------------------------
    87  OrdererOrgs:
    88    # ---------------------------------------------------------------------------
    89    # Orderer
    90    # ---------------------------------------------------------------------------
    91    - Name: Orderer
    92      Domain: example.com
    93  
    94      # ---------------------------------------------------------------------------
    95      # "Specs" - See PeerOrgs below for complete description
    96      # ---------------------------------------------------------------------------
    97      Specs:
    98        - Hostname: orderer
    99  
   100  # ---------------------------------------------------------------------------
   101  # "PeerOrgs" - Definition of organizations managing peer nodes
   102  # ---------------------------------------------------------------------------
   103  PeerOrgs:
   104    # ---------------------------------------------------------------------------
   105    # Org1
   106    # ---------------------------------------------------------------------------
   107    - Name: Org1
   108      Domain: org1.example.com
   109  
   110      # ---------------------------------------------------------------------------
   111      # "Specs"
   112      # ---------------------------------------------------------------------------
   113      # Uncomment this section to enable the explicit definition of hosts in your
   114      # configuration.  Most users will want to use Template, below
   115      #
   116      # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
   117      #   - Hostname:   (Required) The desired hostname, sans the domain.
   118      #   - CommonName: (Optional) Specifies the template or explicit override for
   119      #                 the CN.  By default, this is the template:
   120      #
   121      #                              "{{.Hostname}}.{{.Domain}}"
   122      #
   123      #                 which obtains its values from the Spec.Hostname and
   124      #                 Org.Domain, respectively.
   125      # ---------------------------------------------------------------------------
   126      # Specs:
   127      #   - Hostname: foo # implicitly "foo.org1.example.com"
   128      #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
   129      #   - Hostname: bar
   130      #   - Hostname: baz
   131  
   132      # ---------------------------------------------------------------------------
   133      # "Template"
   134      # ---------------------------------------------------------------------------
   135      # Allows for the definition of 1 or more hosts that are created sequentially
   136      # from a template. By default, this looks like "peer%d" from 0 to Count-1.
   137      # You may override the number of nodes (Count), the starting index (Start)
   138      # or the template used to construct the name (Hostname).
   139      #
   140      # Note: Template and Specs are not mutually exclusive.  You may define both
   141      # sections and the aggregate nodes will be created for you.  Take care with
   142      # name collisions
   143      # ---------------------------------------------------------------------------
   144      Template:
   145        Count: 1
   146        # Start: 5
   147        # Hostname: {{.Prefix}}{{.Index}} # default
   148  
   149      # ---------------------------------------------------------------------------
   150      # "Users"
   151      # ---------------------------------------------------------------------------
   152      # Count: The number of user accounts _in addition_ to Admin
   153      # ---------------------------------------------------------------------------
   154      Users:
   155        Count: 1
   156  
   157    # ---------------------------------------------------------------------------
   158    # Org2: See "Org1" for full specification
   159    # ---------------------------------------------------------------------------
   160    - Name: Org2
   161      Domain: org2.example.com
   162      Template:
   163        Count: 1
   164      Users:
   165        Count: 1
   166  `
   167  
   168  //command line flags
   169  var (
   170  	app = kingpin.New("cryptogen", "Utility for generating Hyperledger Fabric key material")
   171  
   172  	gen        = app.Command("generate", "Generate key material")
   173  	outputDir  = gen.Flag("output", "The output directory in which to place artifacts").Default("crypto-config").String()
   174  	configFile = gen.Flag("config", "The configuration template to use").File()
   175  
   176  	showtemplate = app.Command("showtemplate", "Show the default configuration template")
   177  )
   178  
   179  func main() {
   180  	kingpin.Version("0.0.1")
   181  	switch kingpin.MustParse(app.Parse(os.Args[1:])) {
   182  
   183  	// "generate" command
   184  	case gen.FullCommand():
   185  		generate()
   186  
   187  	// "showtemplate" command
   188  	case showtemplate.FullCommand():
   189  		fmt.Print(defaultConfig)
   190  		os.Exit(0)
   191  	}
   192  
   193  }
   194  
   195  func getConfig() (*Config, error) {
   196  	var configData string
   197  
   198  	if *configFile != nil {
   199  		data, err := ioutil.ReadAll(*configFile)
   200  		if err != nil {
   201  			return nil, fmt.Errorf("Error reading configuration: %s", err)
   202  		}
   203  
   204  		configData = string(data)
   205  	} else {
   206  		configData = defaultConfig
   207  	}
   208  
   209  	config := &Config{}
   210  	err := yaml.Unmarshal([]byte(configData), &config)
   211  	if err != nil {
   212  		return nil, fmt.Errorf("Error Unmarshaling YAML: %s", err)
   213  	}
   214  
   215  	return config, nil
   216  }
   217  
   218  func generate() {
   219  
   220  	config, err := getConfig()
   221  	if err != nil {
   222  		fmt.Printf("Error reading config: %s", err)
   223  		os.Exit(-1)
   224  	}
   225  
   226  	for _, orgSpec := range config.PeerOrgs {
   227  		err = generateNodeSpec(&orgSpec, "peer")
   228  		if err != nil {
   229  			fmt.Printf("Error processing peer configuration: %s", err)
   230  			os.Exit(-1)
   231  		}
   232  		generatePeerOrg(*outputDir, orgSpec)
   233  	}
   234  
   235  	for _, orgSpec := range config.OrdererOrgs {
   236  		generateNodeSpec(&orgSpec, "orderer")
   237  		if err != nil {
   238  			fmt.Printf("Error processing orderer configuration: %s", err)
   239  			os.Exit(-1)
   240  		}
   241  		generateOrdererOrg(*outputDir, orgSpec)
   242  	}
   243  }
   244  
   245  func parseTemplate(input, defaultInput string, data interface{}) (string, error) {
   246  
   247  	// Use the default if the input is an empty string
   248  	if len(input) == 0 {
   249  		input = defaultInput
   250  	}
   251  
   252  	t, err := template.New("parse").Parse(input)
   253  	if err != nil {
   254  		return "", fmt.Errorf("Error parsing template: %s", err)
   255  	}
   256  
   257  	output := new(bytes.Buffer)
   258  	err = t.Execute(output, data)
   259  	if err != nil {
   260  		return "", fmt.Errorf("Error executing template: %s", err)
   261  	}
   262  
   263  	return output.String(), nil
   264  }
   265  
   266  func generateNodeSpec(orgSpec *OrgSpec, prefix string) error {
   267  	// First process all of our templated nodes
   268  	for i := 0; i < orgSpec.Template.Count; i++ {
   269  		data := HostnameData{
   270  			Prefix: prefix,
   271  			Index:  i + orgSpec.Template.Start,
   272  			Domain: orgSpec.Domain,
   273  		}
   274  
   275  		hostname, err := parseTemplate(orgSpec.Template.Hostname, defaultHostnameTemplate, data)
   276  		if err != nil {
   277  			return err
   278  		}
   279  
   280  		spec := NodeSpec{Hostname: hostname}
   281  		orgSpec.Specs = append(orgSpec.Specs, spec)
   282  	}
   283  
   284  	// And finally touch up all specs to add the domain
   285  	for idx, spec := range orgSpec.Specs {
   286  		data := CommonNameData{
   287  			Hostname: spec.Hostname,
   288  			Domain:   orgSpec.Domain,
   289  		}
   290  
   291  		finalCN, err := parseTemplate(spec.CommonName, defaultCNTemplate, data)
   292  		if err != nil {
   293  			return err
   294  		}
   295  
   296  		orgSpec.Specs[idx].CommonName = finalCN
   297  	}
   298  
   299  	return nil
   300  }
   301  
   302  func generatePeerOrg(baseDir string, orgSpec OrgSpec) {
   303  
   304  	orgName := orgSpec.Domain
   305  
   306  	fmt.Println(orgName)
   307  	// generate CA
   308  	orgDir := filepath.Join(baseDir, "peerOrganizations", orgName)
   309  	caDir := filepath.Join(orgDir, "ca")
   310  	mspDir := filepath.Join(orgDir, "msp")
   311  	peersDir := filepath.Join(orgDir, "peers")
   312  	usersDir := filepath.Join(orgDir, "users")
   313  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   314  	rootCA, err := ca.NewCA(caDir, orgName)
   315  	if err != nil {
   316  		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
   317  		os.Exit(1)
   318  	}
   319  	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
   320  	if err != nil {
   321  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   322  		os.Exit(1)
   323  	}
   324  
   325  	peerNames := []string{}
   326  	for _, spec := range orgSpec.Specs {
   327  		peerNames = append(peerNames, spec.CommonName)
   328  	}
   329  	generateNodes(peersDir, peerNames, rootCA)
   330  
   331  	// TODO: add ability to specify usernames
   332  	usernames := []string{}
   333  	for j := 1; j <= orgSpec.Users.Count; j++ {
   334  		usernames = append(usernames, fmt.Sprintf("%s%d@%s",
   335  			userBaseName, j, orgName))
   336  	}
   337  	// add an admin user
   338  	adminUserName := fmt.Sprintf("%s@%s",
   339  		adminBaseName, orgName)
   340  
   341  	usernames = append(usernames, adminUserName)
   342  	generateNodes(usersDir, usernames, rootCA)
   343  
   344  	// copy the admin cert to the org's MSP admincerts
   345  	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
   346  	if err != nil {
   347  		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   348  			orgName, err)
   349  		os.Exit(1)
   350  	}
   351  
   352  	// copy the admin cert to each of the org's peer's MSP admincerts
   353  	for _, peerName := range peerNames {
   354  		err = copyAdminCert(usersDir, filepath.Join(peersDir, peerName,
   355  			"admincerts"), adminUserName)
   356  		if err != nil {
   357  			fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
   358  				orgName, peerName, err)
   359  			os.Exit(1)
   360  		}
   361  	}
   362  }
   363  
   364  func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
   365  	// delete the contents of admincerts
   366  	err := os.RemoveAll(adminCertsDir)
   367  	if err != nil {
   368  		return err
   369  	}
   370  	// recreate the admincerts directory
   371  	err = os.MkdirAll(adminCertsDir, 0755)
   372  	if err != nil {
   373  		return err
   374  	}
   375  	err = copyFile(filepath.Join(usersDir, adminUserName, "signcerts",
   376  		adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
   377  		adminUserName+"-cert.pem"))
   378  	if err != nil {
   379  		return err
   380  	}
   381  	return nil
   382  
   383  }
   384  
   385  func generateNodes(baseDir string, nodeNames []string, rootCA *ca.CA) {
   386  
   387  	for _, nodeName := range nodeNames {
   388  		nodeDir := filepath.Join(baseDir, nodeName)
   389  		err := msp.GenerateLocalMSP(nodeDir, nodeName, rootCA)
   390  		if err != nil {
   391  			fmt.Printf("Error generating local MSP for %s:\n%v\n", nodeName, err)
   392  			os.Exit(1)
   393  		}
   394  	}
   395  
   396  }
   397  
   398  func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {
   399  
   400  	orgName := orgSpec.Domain
   401  
   402  	// generate CA
   403  	orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)
   404  	caDir := filepath.Join(orgDir, "ca")
   405  	mspDir := filepath.Join(orgDir, "msp")
   406  	orderersDir := filepath.Join(orgDir, "orderers")
   407  	usersDir := filepath.Join(orgDir, "users")
   408  	adminCertsDir := filepath.Join(mspDir, "admincerts")
   409  	rootCA, err := ca.NewCA(caDir, orgName)
   410  	if err != nil {
   411  		fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err)
   412  		os.Exit(1)
   413  	}
   414  	err = msp.GenerateVerifyingMSP(mspDir, rootCA)
   415  	if err != nil {
   416  		fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   417  		os.Exit(1)
   418  	}
   419  
   420  	// TODO: add ability to specify orderer names
   421  	// for name just use default base name
   422  	ordererNames := []string{}
   423  	for _, spec := range orgSpec.Specs {
   424  		ordererNames = append(ordererNames, spec.CommonName)
   425  	}
   426  	generateNodes(orderersDir, ordererNames, rootCA)
   427  
   428  	adminUserName := fmt.Sprintf("%s@%s",
   429  		adminBaseName, orgName)
   430  
   431  	// generate an admin for the orderer org
   432  	usernames := []string{}
   433  	// add an admin user
   434  	usernames = append(usernames, adminUserName)
   435  	generateNodes(usersDir, usernames, rootCA)
   436  
   437  	// copy the admin cert to the org's MSP admincerts
   438  	err = copyAdminCert(usersDir, adminCertsDir, adminUserName)
   439  	if err != nil {
   440  		fmt.Printf("Error copying admin cert for org %s:\n%v\n",
   441  			orgName, err)
   442  		os.Exit(1)
   443  	}
   444  
   445  	// copy the admin cert to each of the org's orderers's MSP admincerts
   446  	for _, ordererName := range ordererNames {
   447  		err = copyAdminCert(usersDir, filepath.Join(orderersDir, ordererName,
   448  			"admincerts"), adminUserName)
   449  		if err != nil {
   450  			fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
   451  				orgName, ordererName, err)
   452  			os.Exit(1)
   453  		}
   454  	}
   455  
   456  }
   457  
   458  func copyFile(src, dst string) error {
   459  	in, err := os.Open(src)
   460  	if err != nil {
   461  		return err
   462  	}
   463  	defer in.Close()
   464  	out, err := os.Create(dst)
   465  	if err != nil {
   466  		return err
   467  	}
   468  	defer out.Close()
   469  	_, err = io.Copy(out, in)
   470  	cerr := out.Close()
   471  	if err != nil {
   472  		return err
   473  	}
   474  	return cerr
   475  }