Skip to content
Draft
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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

---

## [Unreleased]

### Added

- Display issuer-validity truncation warnings on stderr after successful native
CA issuance, renewal, rekey, admin login, and SSH-associated X.509 identity
operations, including offline X.509 operations and renewal daemons, without
changing successful exit status
([smallstep/certificates#381](https://github.com/smallstep/certificates/issues/381)).

### Fixed

- Keep certificate warnings nonfatal when stderr is a broken pipe, without
changing process-wide signal handling
([smallstep/certificates#560](https://github.com/smallstep/certificates/issues/560)).
- Display X.509 identity validity warnings during implicit SSH proxy login and
automatic login after an unauthorized response
([smallstep/certificates#560](https://github.com/smallstep/certificates/issues/560)).

## [0.31.0] - 2026-09-25

### Added
Expand Down
6 changes: 6 additions & 0 deletions command/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ func init() {
authority, retrieve the root of trust, sign and renew certificates, and create
and manage provisioners.

Native CA commands print issuer-validity truncation warnings to stderr after
successfully writing or installing the issued credentials, without changing
successful exit status. Administrative commands also report these warnings
when login creates a new in-memory admin identity; existing admin credentials
do not trigger issuance warnings.

## EXAMPLES

Create the configuration for a new certificate authority:
Expand Down
5 changes: 5 additions & 0 deletions command/ca/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func certificateCommand() cli.Command {
[**--context**=<name>]`,
Description: `**step ca certificate** command generates a new certificate pair

For native CA issuance, including **--offline**, issuer-validity truncation
warnings are printed to stderr after the certificate is written. These warnings
do not change successful exit status. ACME issuance does not provide native CA
warning metadata.

## POSITIONAL ARGUMENTS

<subject>
Expand Down
4 changes: 4 additions & 0 deletions command/ca/rekey.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ to disk - either overwriting <crt-file> and <key-file> positional arguments
or using new files when the **--out-cert**=<file> and **--out-key**=<file>
flags are used.

Issuer-validity truncation warnings are printed to stderr after the certificate
and key are written, including daemon rekeys. These warnings do not change
successful exit status.

With the **--daemon** flag the command will periodically update the given
certificate. By default, it will rekey the certificate before 2/3 of the validity
period of the certificate has elapsed. A random jitter is used to avoid multiple
Expand Down
9 changes: 9 additions & 0 deletions command/ca/renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,19 @@ func renewCertificateCommand() cli.Command {
certificate authority) and writes the new certificate to disk - either overwriting
<crt-file> or using a new file when the **--out**=<file> flag is used.

Issuer-validity truncation warnings are printed to stderr after the renewed
certificate is written, including offline and daemon renewals. These warnings
do not change successful exit status.

With the **--daemon** flag the command will periodically update the given
certificate. By default, it will renew the certificate before 2/3 of the validity
period of the certificate has elapsed. A random jitter is used to avoid multiple
instances running at the same time. The amount of time between renewal and
certificate expiration can be configured using the **--expires-in** flag, or a
fixed period can be set with the **--renew-period** flag.
If issuer validity shortens the certificate lifetime below a fixed renewal
period, the existing scheduling policy renews immediately. Renewal preserves
the previous certificate's duration, including an earlier truncated duration.

The **--daemon** flag can be combined with **--pid**, **--signal**, or **--exec**
to provide certificate reloads on your services.
Expand Down Expand Up @@ -503,6 +510,7 @@ func (r *renewer) Renew(outFile string) (resp *api.SignResponse, err error) {
return nil, errs.FileError(err, outFile)
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return resp, nil
}

Expand Down Expand Up @@ -540,6 +548,7 @@ func (r *renewer) Rekey(priv any, outCert, outKey string, writePrivateKey bool)
}
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return resp, nil
}

Expand Down
5 changes: 5 additions & 0 deletions command/ca/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ func signCertificateCommand() cli.Command {
[**--root**=<file>] [**--context**=<name>]`,
Description: `**step ca sign** command signs the given csr and generates a new certificate.

For native CA issuance, including **--offline**, issuer-validity truncation
warnings are printed to stderr after the certificate is written. These warnings
do not change successful exit status. ACME issuance does not provide native CA
warning metadata.

## POSITIONAL ARGUMENTS

<csr-file>
Expand Down
6 changes: 6 additions & 0 deletions command/ssh/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ certificate using [step certificates](https://github.com/smallstep/certificates)
With a certificate clients or servers may trust only the CA key and verify its
signature on a certificate rather than trusting many user/host keys.

When the CA also issues an X.509 identity, issuer-validity truncation warnings
are printed to stderr after the credentials are written. These warnings do not
change successful exit status or the SSH certificate's validity. Offline SSH
issuance does not issue an X.509 identity.

Note that not all the provisioner types will be able to generate user and host
certificates. Currently JWK provisioners can generate both, but with an OIDC
provisioner you will only be able to generate user certificates unless you are
Expand Down Expand Up @@ -545,6 +550,7 @@ func certificateAction(ctx *cli.Context) error {
ui.PrintSelected("Add User Certificate", baseName+"-provisioner-cert.pub")
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return nil
}

Expand Down
7 changes: 7 additions & 0 deletions command/ssh/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ssh

import (
"crypto"
"os"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -41,6 +42,11 @@ certificate. This certificate will be automatically added to the SSH agent.
With a certificate servers may trust only the CA key and verify its signature on
a certificate rather than trusting many user keys.

When the CA also issues an X.509 identity, issuer-validity truncation warnings
are printed to stderr after the identity is installed. These warnings do not
change successful exit status or the SSH certificate's validity. Offline SSH
issuance does not issue an X.509 identity.

## POSITIONAL ARGUMENTS

<identity>
Expand Down Expand Up @@ -298,5 +304,6 @@ func loginAction(ctx *cli.Context) error {
}
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return nil
}
13 changes: 11 additions & 2 deletions command/ssh/proxycommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func proxycommandCommand() cli.Command {
and proxies the ssh connection according to its configuration. This command
is used in the ssh client config with <ProxyCommand> keyword.

This command will add the user to the ssh-agent if necessary.
This command will add the user to the ssh-agent if necessary. When the CA also
issues an X.509 identity, issuer-validity truncation warnings are printed to
stderr after the identity is installed. These warnings do not change successful
exit status or the SSH certificate's validity. Offline SSH issuance does not
issue an X.509 identity.

## POSITIONAL ARGUMENTS

Expand Down Expand Up @@ -212,7 +216,12 @@ func doLoginIfNeeded(ctx *cli.Context, subject string) error {
}

// Add certificate and private key to agent
return agent.AddCertificate(subject, resp.Certificate.Certificate, priv)
if err := agent.AddCertificate(subject, resp.Certificate.Certificate, priv); err != nil {
return err
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return nil
}

func getBastion(ctx *cli.Context, user, host string) (*api.SSHBastionResponse, error) {
Expand Down
6 changes: 6 additions & 0 deletions command/ssh/rekey.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ an existing SSH Certificate and key pair to authenticate and templatize the
request. It writes the new certificate to disk - either overwriting
<ssh-cert> or using new files when the **--out**=<file> flag is used.

When the CA also renews an X.509 identity, issuer-validity truncation warnings
are printed to stderr after the credentials are written. These warnings do not
change successful exit status or the SSH certificate's validity. Offline SSH
rekey does not renew an X.509 identity.

## POSITIONAL ARGUMENTS

<ssh-cert>
Expand Down Expand Up @@ -194,5 +199,6 @@ func rekeyAction(ctx *cli.Context) error {
ui.PrintSelected("Public Key", newPubFile)
ui.PrintSelected("Certificate", newCertFile)

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return nil
}
6 changes: 6 additions & 0 deletions command/ssh/renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ It writes the new certificate to disk - either overwriting <ssh-cert> or
using a new file when the **--out**=<file> flag is used. This command cannot
be used to renew SSH User Certificates.

When the CA also renews an X.509 identity, issuer-validity truncation warnings
are printed to stderr after the credentials are written. These warnings do not
change successful exit status or the SSH certificate's validity. Offline SSH
renewal does not renew an X.509 identity.

## POSITIONAL ARGUMENTS

<ssh-cert>
Expand Down Expand Up @@ -141,5 +146,6 @@ func renewAction(ctx *cli.Context) error {

ui.PrintSelected("Certificate", outFile)

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return nil
}
7 changes: 7 additions & 0 deletions command/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ssh

import (
"net/http"
"os"
"strings"

"github.com/pkg/errors"
Expand Down Expand Up @@ -30,6 +31,11 @@ func init() {
UsageText: "step ssh <subcommand> [arguments] [global-flags] [subcommand-flags]",
Description: `**step ssh** command group provides facilities to sign SSH certificates.

When automatic login issues an X.509 identity, issuer-validity truncation
warnings are printed to stderr after the identity is installed, including login
while recovering from an unauthorized response. Warning output does not change
successful exit status or SSH certificate validity.

## EXAMPLES

Generate a new SSH key pair and user certificate:
Expand Down Expand Up @@ -247,6 +253,7 @@ func loginOnUnauthorized(ctx *cli.Context) (ca.RetryFunc, error) {
agent.AddCertificate(jwt.Payload.Email, resp.Certificate.Certificate, priv)
}

cautils.PrintCertificateWarnings(os.Stderr, resp.Warnings)
return true
}, nil
}
Expand Down
Loading
Loading