Skip to content

Commit

Permalink
cmd/genbotcert, buildenv: add certificate creation to genbotcert
Browse files Browse the repository at this point in the history
genbotcert can now use a certificate signing request to create a
certificate with the Go teams CA. These certificates should be used to
authenticate contributor managed swarming bots in Luci. It can also
be used to add general non-GCE swarming bots.

Initial Luci production environment settings have been added to the
buildenv package.

Updates golang/go#60640

Change-Id: I9ad9150ac332ea79413bf556b0830f343646848f
Reviewed-on: https://go-review.googlesource.com/c/build/+/504531
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Carlos Amedee <carlos@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Run-TryBot: Carlos Amedee <carlos@golang.org>
  • Loading branch information
cagedmantis authored and gopherbot committed Jun 28, 2023
1 parent a747220 commit 388349a
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 220 deletions.
6 changes: 6 additions & 0 deletions buildenv/envs.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,12 @@ var Production = &Environment{
GomoteTransferBucket: "gomote-transfer",
}

var LUCIProduction = &Environment{
ProjectName: "golang-ci-luci",
ProjectNumber: 257595674695,
IsProd: true,
}

var Development = &Environment{
GoProjectName: "golang-org",
IsProd: false,
Expand Down
87 changes: 79 additions & 8 deletions cmd/genbotcert/genbotcert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Command genbotcert generates a private key and CSR for a LUCI bot.
// It accepts one argument, the bot hostname, and writes the PEM-encoded
// results to the current working directory.
// Command genbotcert can both generate a CSR and private key for a LUCI bot
// and generate a certificate from a CSR. It accepts two arguments, the
// bot hostname, and the path to the CSR. If it only receives the hostname then
// it writes the PEM-encoded CSR to the current working directory along with
// a private key. If it receives both the hostname and CSR path then it
// validates that the hostname is what is what is expected in the CSR and
// generates a certificate. The certificate is written to the current working
// directory.
package main

import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
Expand All @@ -17,25 +23,42 @@ import (
"fmt"
"log"
"os"
"time"

privateca "cloud.google.com/go/security/privateca/apiv1"
"cloud.google.com/go/security/privateca/apiv1/privatecapb"
"golang.org/x/build/buildenv"
"google.golang.org/protobuf/types/known/durationpb"
)

var (
csrPath = flag.String("csr-path", "", "Path to the certificate signing request (required for certificate)")
botHostname = flag.String("bot-hostname", "", "Hostname for the bot (required)")
)

func main() {
flag.Usage = func() {
fmt.Fprintln(os.Stderr, "Usage: genbotcert <bot-hostname>")
fmt.Fprintln(os.Stderr, "Usage: genbotcert -bot-hostname <bot-hostname>")
flag.PrintDefaults()
}
flag.Parse()
if flag.NArg() != 1 {
if *botHostname == "" {
flag.Usage()
os.Exit(2)
}

if err := doMain(flag.Arg(0)); err != nil {
ctx := context.Background()
var err error
if *csrPath == "" {
err = doMain(ctx, *botHostname)
} else {
err = generateCert(ctx, *botHostname, *csrPath)
}
if err != nil {
log.Fatalln(err)
}
}

func doMain(cn string) error {
func doMain(ctx context.Context, cn string) error {
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return err
Expand Down Expand Up @@ -74,3 +97,51 @@ func doMain(cn string) error {
fmt.Printf("Wrote CSR to %v.csr and key to %v.key\n", cn, cn)
return nil
}

func generateCert(ctx context.Context, hostname, csrPath string) error {
csr, err := os.ReadFile(csrPath)
if err != nil {
return fmt.Errorf("unable to read file %q: %s", csrPath, err)
}
// validate hostname
pb, _ := pem.Decode(csr)
cr, err := x509.ParseCertificateRequest(pb.Bytes)
if err != nil {
return fmt.Errorf("unable to parse certificate request: %w", err)
}
if cr.Subject.CommonName != fmt.Sprintf("%s.bots.golang.org", hostname) {
return fmt.Errorf("certificate signing request does not match hostname: want %q, got %q", hostname, cr.Subject.CommonName)
}
certId := fmt.Sprintf("%s-%d", hostname, time.Now().Unix()) // A unique name for the certificate.
caClient, err := privateca.NewCertificateAuthorityClient(ctx)
if err != nil {
return fmt.Errorf("NewCertificateAuthorityClient creation failed: %w", err)
}
defer caClient.Close()
fullCaPoolName := fmt.Sprintf("projects/%s/locations/%s/caPools/%s", buildenv.LUCIProduction.ProjectName, "us-central1", "default-pool")
// Create the CreateCertificateRequest.
// See https://pkg.go.dev/cloud.google.com/go/security/privateca/apiv1/privatecapb#CreateCertificateRequest.
req := &privatecapb.CreateCertificateRequest{
Parent: fullCaPoolName,
CertificateId: certId,
Certificate: &privatecapb.Certificate{
CertificateConfig: &privatecapb.Certificate_PemCsr{
PemCsr: string(csr),
},
Lifetime: &durationpb.Duration{
Seconds: 315360000, // Seconds in 10 years.
},
},
IssuingCertificateAuthorityId: "luci-bot-ca", // The name of the certificate authority which issues the certificate.
}
resp, err := caClient.CreateCertificate(ctx, req)
if err != nil {
return fmt.Errorf("CreateCertificate failed: %w", err)
}
log.Printf("Certificate %s created", certId)
if err := os.WriteFile(hostname+".cert", []byte(resp.PemCertificate), 0600); err != nil {
return fmt.Errorf("unable to write certificate to disk: %s", err)
}
fmt.Printf("Wrote certificate to %s.cert\n", certId)
return nil
}
84 changes: 51 additions & 33 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ module golang.org/x/build
go 1.18

require (
cloud.google.com/go/bigquery v1.42.0
cloud.google.com/go/compute v1.10.0
cloud.google.com/go/datastore v1.1.0
cloud.google.com/go/errorreporting v0.2.0
cloud.google.com/go/pubsub v1.26.0
cloud.google.com/go/secretmanager v1.6.0
cloud.google.com/go/storage v1.23.0
cloud.google.com/go/bigquery v1.50.0
cloud.google.com/go/compute/metadata v0.2.3
cloud.google.com/go/datastore v1.11.0
cloud.google.com/go/errorreporting v0.3.0
cloud.google.com/go/pubsub v1.30.0
cloud.google.com/go/secretmanager v1.10.0
cloud.google.com/go/security v1.15.0
cloud.google.com/go/storage v1.29.0
contrib.go.opencensus.io/exporter/prometheus v0.4.2
contrib.go.opencensus.io/exporter/stackdriver v0.13.5
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf
Expand All @@ -24,13 +25,13 @@ require (
github.com/gliderlabs/ssh v0.3.3
github.com/go-sql-driver/mysql v1.5.0
github.com/golang-migrate/migrate/v4 v4.15.0-beta.3
github.com/golang/protobuf v1.5.2
github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-github/v48 v48.1.0
github.com/google/safehtml v0.0.3-0.20220430015336-00016cfeca15
github.com/google/uuid v1.3.0
github.com/googleapis/gax-go/v2 v2.6.0
github.com/googleapis/gax-go/v2 v2.10.0
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
Expand All @@ -46,51 +47,60 @@ require (
github.com/shurcooL/githubv4 v0.0.0-20220520033151-0b4e3294ff00
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
github.com/yuin/goldmark v1.4.13
go.opencensus.io v0.23.0
go.opencensus.io v0.24.0
go4.org v0.0.0-20180809161055-417644f6feb5
golang.org/x/crypto v0.1.0
golang.org/x/crypto v0.9.0
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91
golang.org/x/image v0.5.0
golang.org/x/mod v0.6.0
golang.org/x/net v0.7.0
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783
golang.org/x/mod v0.8.0
golang.org/x/net v0.10.0
golang.org/x/oauth2 v0.8.0
golang.org/x/perf v0.0.0-20221222170352-3fd27c239283
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
golang.org/x/sys v0.5.0
golang.org/x/term v0.5.0
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af
golang.org/x/tools v0.2.0
google.golang.org/api v0.99.0
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0
golang.org/x/term v0.8.0
golang.org/x/time v0.3.0
golang.org/x/tools v0.6.0
google.golang.org/api v0.125.0
google.golang.org/appengine v1.6.7
google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e
google.golang.org/grpc v1.50.1
google.golang.org/protobuf v1.28.1
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc
google.golang.org/grpc v1.55.0
google.golang.org/protobuf v1.30.0
gopkg.in/inf.v0 v0.9.1
)

require (
cloud.google.com/go v0.104.0 // indirect
cloud.google.com/go/container v1.2.0 // indirect
cloud.google.com/go/iam v0.5.0 // indirect
cloud.google.com/go/monitoring v1.4.0 // indirect
cloud.google.com/go/trace v1.2.0 // indirect
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go/container v1.15.0 // indirect
cloud.google.com/go/iam v1.0.1 // indirect
cloud.google.com/go/longrunning v0.4.2 // indirect
cloud.google.com/go/monitoring v1.13.0 // indirect
cloud.google.com/go/trace v1.9.0 // indirect
github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/apache/arrow/go/v11 v11.0.0 // indirect
github.com/apache/thrift v0.16.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/census-instrumentation/opencensus-proto v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/fogleman/gg v1.3.0 // indirect
github.com/go-fonts/liberation v0.2.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-pdf/fpdf v0.5.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v2.0.8+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
github.com/googleapis/go-type-adapters v1.0.0 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
Expand All @@ -103,7 +113,13 @@ require (
github.com/jackc/pgtype v1.8.1 // indirect
github.com/jackc/puddle v1.1.3 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
github.com/klauspost/compress v1.15.9 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.13.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
Expand All @@ -112,9 +128,11 @@ require (
github.com/prometheus/statsd_exporter v0.22.7 // indirect
github.com/sendgrid/rest v2.6.9+incompatible // indirect
github.com/shurcooL/graphql v0.0.0-20220520033453-bdb1221e171e // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.uber.org/atomic v1.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
gonum.org/v1/plot v0.10.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Loading

0 comments on commit 388349a

Please sign in to comment.