github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/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 CA 385 orgDir := filepath.Join(baseDir, "peerOrganizations", orgName) 386 caDir := filepath.Join(orgDir, "ca") 387 mspDir := filepath.Join(orgDir, "msp") 388 peersDir := filepath.Join(orgDir, "peers") 389 usersDir := filepath.Join(orgDir, "users") 390 adminCertsDir := filepath.Join(mspDir, "admincerts") 391 rootCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName) 392 if err != nil { 393 fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err) 394 os.Exit(1) 395 } 396 err = msp.GenerateVerifyingMSP(mspDir, rootCA) 397 if err != nil { 398 fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) 399 os.Exit(1) 400 } 401 402 generateNodes(peersDir, orgSpec.Specs, rootCA) 403 404 // TODO: add ability to specify usernames 405 users := []NodeSpec{} 406 for j := 1; j <= orgSpec.Users.Count; j++ { 407 user := NodeSpec{ 408 CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName), 409 } 410 411 users = append(users, user) 412 } 413 // add an admin user 414 adminUser := NodeSpec{ 415 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 416 } 417 418 users = append(users, adminUser) 419 generateNodes(usersDir, users, rootCA) 420 421 // copy the admin cert to the org's MSP admincerts 422 err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName) 423 if err != nil { 424 fmt.Printf("Error copying admin cert for org %s:\n%v\n", 425 orgName, err) 426 os.Exit(1) 427 } 428 429 // copy the admin cert to each of the org's peer's MSP admincerts 430 for _, spec := range orgSpec.Specs { 431 err = copyAdminCert(usersDir, 432 filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 433 if err != nil { 434 fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n", 435 orgName, spec.CommonName, err) 436 os.Exit(1) 437 } 438 } 439 } 440 441 func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error { 442 // delete the contents of admincerts 443 err := os.RemoveAll(adminCertsDir) 444 if err != nil { 445 return err 446 } 447 // recreate the admincerts directory 448 err = os.MkdirAll(adminCertsDir, 0755) 449 if err != nil { 450 return err 451 } 452 err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts", 453 adminUserName+"-cert.pem"), filepath.Join(adminCertsDir, 454 adminUserName+"-cert.pem")) 455 if err != nil { 456 return err 457 } 458 return nil 459 460 } 461 462 func generateNodes(baseDir string, nodes []NodeSpec, rootCA *ca.CA) { 463 464 for _, node := range nodes { 465 nodeDir := filepath.Join(baseDir, node.CommonName) 466 err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, rootCA) 467 if err != nil { 468 fmt.Printf("Error generating local MSP for %s:\n%v\n", node, err) 469 os.Exit(1) 470 } 471 } 472 } 473 474 func generateOrdererOrg(baseDir string, orgSpec OrgSpec) { 475 476 orgName := orgSpec.Domain 477 478 // generate CA 479 orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName) 480 caDir := filepath.Join(orgDir, "ca") 481 mspDir := filepath.Join(orgDir, "msp") 482 orderersDir := filepath.Join(orgDir, "orderers") 483 usersDir := filepath.Join(orgDir, "users") 484 adminCertsDir := filepath.Join(mspDir, "admincerts") 485 rootCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName) 486 if err != nil { 487 fmt.Printf("Error generating CA for org %s:\n%v\n", orgName, err) 488 os.Exit(1) 489 } 490 err = msp.GenerateVerifyingMSP(mspDir, rootCA) 491 if err != nil { 492 fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err) 493 os.Exit(1) 494 } 495 496 generateNodes(orderersDir, orgSpec.Specs, rootCA) 497 498 adminUser := NodeSpec{ 499 CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName), 500 } 501 502 // generate an admin for the orderer org 503 users := []NodeSpec{} 504 // add an admin user 505 users = append(users, adminUser) 506 generateNodes(usersDir, users, rootCA) 507 508 // copy the admin cert to the org's MSP admincerts 509 err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName) 510 if err != nil { 511 fmt.Printf("Error copying admin cert for org %s:\n%v\n", 512 orgName, err) 513 os.Exit(1) 514 } 515 516 // copy the admin cert to each of the org's orderers's MSP admincerts 517 for _, spec := range orgSpec.Specs { 518 err = copyAdminCert(usersDir, 519 filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName) 520 if err != nil { 521 fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n", 522 orgName, spec.CommonName, err) 523 os.Exit(1) 524 } 525 } 526 527 } 528 529 func copyFile(src, dst string) error { 530 in, err := os.Open(src) 531 if err != nil { 532 return err 533 } 534 defer in.Close() 535 out, err := os.Create(dst) 536 if err != nil { 537 return err 538 } 539 defer out.Close() 540 _, err = io.Copy(out, in) 541 cerr := out.Close() 542 if err != nil { 543 return err 544 } 545 return cerr 546 } 547 548 func printVersion() { 549 fmt.Println(metadata.GetVersionInfo()) 550 }