in pkg/berglas/bootstrap.go [102:225]
func (c *Client) storageBootstrap(ctx context.Context, i *StorageBootstrapRequest) error {
projectID := i.ProjectID
if projectID == "" {
return fmt.Errorf("missing project ID")
}
bucket := i.Bucket
if bucket == "" {
return fmt.Errorf("missing bucket name")
}
bucketLocation := strings.ToUpper(i.BucketLocation)
if bucketLocation == "" {
bucketLocation = "US"
}
kmsLocation := i.KMSLocation
if kmsLocation == "" {
kmsLocation = "global"
}
kmsKeyRing := i.KMSKeyRing
if kmsKeyRing == "" {
kmsKeyRing = "berglas"
}
kmsCryptoKey := i.KMSCryptoKey
if kmsCryptoKey == "" {
kmsCryptoKey = "berglas-key"
}
logger := logging.FromContext(ctx).With(
"project_id", projectID,
"bucket", bucket,
"bucket_location", bucketLocation,
"kms_location", kmsLocation,
"kms_key_ring", kmsKeyRing,
"kms_crypto_key", kmsCryptoKey,
)
logger.DebugContext(ctx, "bootstrap.start")
defer logger.DebugContext(ctx, "bootstrap.finish")
// Create the KMS key ring
logger.DebugContext(ctx, "creating KMS key ring")
if _, err := c.kmsClient.CreateKeyRing(ctx, &kmspb.CreateKeyRingRequest{
Parent: fmt.Sprintf("projects/%s/locations/%s",
projectID, kmsLocation),
KeyRingId: kmsKeyRing,
}); err != nil {
logger.ErrorContext(ctx, "failed to create KMS key ring", "error", err)
terr, ok := grpcstatus.FromError(err)
if !ok || terr.Code() != grpccodes.AlreadyExists {
return fmt.Errorf("failed to create KMS key ring %s: %w", kmsKeyRing, err)
}
}
// Create the KMS crypto key
logger.DebugContext(ctx, "creating KMS crypto key")
rotationPeriod := 30 * 24 * time.Hour
if _, err := c.kmsClient.CreateCryptoKey(ctx, &kmspb.CreateCryptoKeyRequest{
Parent: fmt.Sprintf("projects/%s/locations/%s/keyRings/%s",
projectID, kmsLocation, kmsKeyRing),
CryptoKeyId: kmsCryptoKey,
CryptoKey: &kmspb.CryptoKey{
Purpose: kmspb.CryptoKey_ENCRYPT_DECRYPT,
RotationSchedule: &kmspb.CryptoKey_RotationPeriod{
RotationPeriod: &durationpb.Duration{
Seconds: int64(rotationPeriod.Seconds()),
},
},
NextRotationTime: ×tamppb.Timestamp{
Seconds: time.Now().Add(time.Duration(rotationPeriod)).Unix(),
},
VersionTemplate: &kmspb.CryptoKeyVersionTemplate{
Algorithm: kmspb.CryptoKeyVersion_GOOGLE_SYMMETRIC_ENCRYPTION,
ProtectionLevel: kmspb.ProtectionLevel_SOFTWARE,
},
},
}); err != nil {
logger.ErrorContext(ctx, "failed to create KMS crypto key", "error", err)
terr, ok := grpcstatus.FromError(err)
if !ok || terr.Code() != grpccodes.AlreadyExists {
return fmt.Errorf("failed to create KMS crypto key %s: %w", kmsCryptoKey, err)
}
}
// Create the storage bucket
logger.DebugContext(ctx, "creating bucket")
if err := c.storageClient.Bucket(bucket).Create(ctx, projectID, &storage.BucketAttrs{
PredefinedACL: "private",
PredefinedDefaultObjectACL: "private",
Location: bucketLocation,
VersioningEnabled: true,
Lifecycle: storage.Lifecycle{
Rules: []storage.LifecycleRule{
{
Action: storage.LifecycleAction{
Type: "Delete",
},
Condition: storage.LifecycleCondition{
NumNewerVersions: 10,
},
},
},
},
Labels: map[string]string{
"purpose": "berglas",
},
}); err != nil {
logger.ErrorContext(ctx, "failed to create bucket", "error", err)
if !isBucketAlreadyExistsError(err) {
return fmt.Errorf("failed to create storage bucket %s: %w", bucket, err)
}
}
return nil
}