Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,38 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [x.y.z] - TBD

### Deprecated

- Creating new Linked CA deployments via `step ca init --deployment-type=linked`
is no longer supported in open-source step-ca. Users requiring Linked CA
features should use Step CA Pro. See https://smallstep.com/product/step-ca-pro/

#### Migrating from Linked CA to Standalone

To migrate an existing linked CA to standalone mode:

1. Export your current configuration including cloud-stored provisioners:
```
step-ca export $(step path)/config/ca.json --token $STEP_CA_TOKEN > export.json
```

2. Stop the CA

3. Update your `ca.json`:
- Remove the `authority.linkedca` section
- Ensure `authority.enableAdmin: true`
- Ensure `db` is configured

4. Import the provisioners and admins:
```
step-ca import $(step path)/config/ca.json export.json
```

5. Start the CA without the `--token` flag:
```
step-ca $(step path)/config/ca.json
```

### Changed

- Suppress output messages for `step certificate needs-renewal` and `step ssh
Expand Down
42 changes: 18 additions & 24 deletions command/ca/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,15 @@ func initCommand() cli.Command {
Choose standalone if you'd like to run step-ca yourself and do not want
cloud services or commercial support.

**linked**
: An instance of step-ca with locally managed keys that connects to your
Certificate Manager account for provisioner management, alerting,
reporting, revocation, and other managed services.
Choose linked if you'd like cloud services and support, but need to
control your authority's signing keys.

**hosted**
: A highly available, fully-managed instance of step-ca run by smallstep
just for you.
Choose hosted if you'd like cloud services and support.

: More information and pricing at: https://u.step.sm/cm`,
: More information and pricing at: https://u.step.sm/cm

: Note: Linked CA deployment type is available in Step CA Pro.
See https://smallstep.com/product/step-ca-pro/`,
},
cli.StringFlag{
Name: "name",
Expand Down Expand Up @@ -445,10 +441,7 @@ func initAction(ctx *cli.Context) (err error) {
ui.Println()
return nil
}
// When initializing a linked CA, providing the --acme flag doesn't currently
// result in the default ACME provisioner being added. We may want to support this
// for ease of use, but this seems to require a bit of refactoring when generating
// the full CA configuration with DB initialization.
// The --acme flag is only supported with standalone deployments.
if deploymentType != pki.StandaloneDeployment && addDefaultACMEProvisioner {
return fmt.Errorf("adding a default ACME provisioner by providing the --acme flag is not supported with deployment type %q.\nPlease use `step ca provisioner add acme --type ACME` after initializing your CA", deploymentType.String())
}
Expand Down Expand Up @@ -606,9 +599,7 @@ func initAction(ctx *cli.Context) (err error) {
pki.WithSuperAdminSubject(firstSuperAdminSubject),
)
}
if deploymentType == pki.LinkedDeployment {
pkiOpts = append(pkiOpts, pki.WithAdmin())
} else if ctx.Bool("ssh") {
if ctx.Bool("ssh") {
pkiOpts = append(pkiOpts, pki.WithSSH())
}
if noDB {
Expand Down Expand Up @@ -638,7 +629,7 @@ func initAction(ctx *cli.Context) (err error) {
// but this is not common on RA mode.
ui.Println("Choose a password for your first provisioner.", ui.WithValue(password))
} else {
// Linked CAs will use OIDC as a first provisioner.
// Hosted deployments use a different provisioner setup.
if pkiOnly || deploymentType != pki.StandaloneDeployment {
ui.Println("Choose a password for your CA keys.", ui.WithValue(password))
} else {
Expand Down Expand Up @@ -767,35 +758,38 @@ func promptDeploymentType(ctx *cli.Context, isRA bool) (pki.DeploymentType, erro
return pki.StandaloneDeployment, nil
}

// Linked deployment type is no longer available in open-source step-ca.
// It is available in Step CA Pro. See https://smallstep.com/product/step-ca-pro/
if deploymentType == "linked" {
return 0, errors.New("Creating new Linked CAs is no longer supported in open-source step-ca.\n" +
"Linked CA functionality is available in Step CA Pro.\n" +
"See: https://smallstep.com/product/step-ca-pro/")
}

deploymentTypes = []deployment{
{"Standalone", "step-ca instance you run yourself", pki.StandaloneDeployment},
{"Linked", "standalone, plus cloud configuration, reporting & alerting", pki.LinkedDeployment},
{"Hosted", "fully-managed step-ca cloud instance run for you by smallstep", pki.HostedDeployment},
}

if isRA {
switch deploymentType {
case "":
// Deployment type Hosted is not supported for RAs
deploymentTypes = deploymentTypes[:2]
deploymentTypes = deploymentTypes[:1]
case "standalone":
return pki.StandaloneDeployment, nil
case "linked":
return pki.LinkedDeployment, nil
default:
return 0, errs.InvalidFlagValue(ctx, "deployment-type", deploymentType, "standalone or linked")
return 0, errs.InvalidFlagValue(ctx, "deployment-type", deploymentType, "standalone")
}
} else {
switch deploymentType {
case "":
case "standalone":
return pki.StandaloneDeployment, nil
case "linked":
return pki.LinkedDeployment, nil
case "hosted":
return pki.HostedDeployment, nil
default:
return 0, errs.InvalidFlagValue(ctx, "deployment-type", deploymentType, "standalone, linked or hosted")
return 0, errs.InvalidFlagValue(ctx, "deployment-type", deploymentType, "standalone or hosted")
}
}

Expand Down
83 changes: 83 additions & 0 deletions command/ca/init_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package ca

import (
"flag"
"reflect"
"testing"

"github.com/smallstep/certificates/pki"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
_ "go.step.sm/crypto/kms/azurekms"
)

Expand Down Expand Up @@ -119,3 +123,82 @@ func Test_processDNSValue(t *testing.T) {
})
}
}

func Test_promptDeploymentType(t *testing.T) {
app := &cli.App{}

tests := []struct {
name string
deploymentType string
isRA bool
want pki.DeploymentType
wantErr string
}{
{
name: "ok/standalone",
deploymentType: "standalone",
isRA: false,
want: pki.StandaloneDeployment,
},
{
name: "ok/standalone-ra",
deploymentType: "standalone",
isRA: true,
want: pki.StandaloneDeployment,
},
{
name: "ok/hosted",
deploymentType: "hosted",
isRA: false,
want: pki.HostedDeployment,
},
{
name: "fail/linked-deprecated",
deploymentType: "linked",
isRA: false,
wantErr: "Creating new Linked CAs is no longer supported in open-source step-ca",
},
{
name: "fail/linked-deprecated-ra",
deploymentType: "linked",
isRA: true,
wantErr: "Creating new Linked CAs is no longer supported in open-source step-ca",
},
{
name: "fail/invalid-type",
deploymentType: "invalid",
isRA: false,
wantErr: "invalid value",
},
{
name: "fail/invalid-type-ra",
deploymentType: "invalid",
isRA: true,
wantErr: "invalid value",
},
{
name: "fail/hosted-ra",
deploymentType: "hosted",
isRA: true,
wantErr: "invalid value",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
set := flag.NewFlagSet("test", 0)
_ = set.String("deployment-type", "", "")
ctx := cli.NewContext(app, set, nil)
_ = ctx.Set("deployment-type", tt.deploymentType)

got, err := promptDeploymentType(ctx, tt.isRA)
if tt.wantErr != "" {
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
}
})
}
}
Loading