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 }