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 }