資格情報のローテーション

Vault の包括的な認証情報ローテーション機能により、データベース認証情報などの機密情報の自動更新とローテーションが可能になります。アプリケーションインスタンスのライフサイクルに機密情報の有効性を紐付けることで、アプリケーションは手動操作なしで有効な認証情報へのアクセスを維持できます。侵害された認証情報は限られた期間のみ有効であり、影響は単一のアプリケーションインスタンスに限定されます。

秘密情報にリース期間が設定されている場合、Spring Vault は有効期限が切れる前にそのリースを更新し、アプリケーションのライフサイクル全体を通して認証情報を有効に保ちます。

以下のセクションでは、プロパティソースなどのコンポーネントで使用される認証情報ローテーションインフラストラクチャについて説明します。

SecretLeaseContainer

SecretLeaseContainer は、リースされたシークレットのライフサイクルを管理します。リースの有効期限が切れる前にリースを更新し、必要に応じて認証情報をローテーションします。また、リースイベントを監視し、適切なアクションを実行します。

Spring Lifecycle コンポーネントとして、コンテナーはアプリケーション実行時の動的なシークレット管理をサポートします。管理対象のシークレットを表す RequestedSecret (Javadoc) インスタンスを受け入れます。

例 1: SecretLeaseContainer の設定
SecretLeaseContainer container = new SecretLeaseContainer(vaultOperations,       (1)
    taskScheduler);

RequestedSecret requestedSecret = container                                      (2)
    .requestRotatingSecret("mysql/creds/my-role");

container.addLeaseListener(new LeaseListenerAdapter() {                          (3)

  @Override
  public void onLeaseEvent(SecretLeaseEvent secretLeaseEvent) {
    if (requestedSecret.equals(secretLeaseEvent.getSource())) {
      if (secretLeaseEvent instanceof SecretLeaseCreatedEvent) {
        // …
      }
      if (secretLeaseEvent instanceof SecretLeaseExpiredEvent) {
        // …
      }
    }
  }
});
container.afterPropertiesSet();
container.start(); // events are triggered after starting the container
1 更新スケジュールのために、VaultOperations と TaskScheduler で初期化します。
2Vault パスからローテーションシークレットをリクエストします。
3 リースイベント用に LeaseListener を登録してください。登録順序が重要です。コンテナー起動後またはシークレットリクエスト後にリスナーを追加すると、初期のイベントを見逃す可能性があります。すべてのイベントをキャプチャーするには、コンテナー起動前にリスナーを設定してください。
SecretLaseContainer は、構成クラスが AbstractVaultConfiguration のサブクラスである場合に登録されます。これは通常、Spring Boot 以外のアプリケーションに適用されます。Spring Boot を使用する場合は、自動構成による登録を処理する Spring Cloud Vault [GitHub] (英語) を検討してください。

イベント

定期イベント

エラーイベント

SecretLeaseContainer をリスナーと直接使用することで、シークレットのライフサイクルとリースイベントの処理をきめ細かく制御できます。しかし、一般的なアプリケーションシナリオでは、シークレットとそのリース管理を簡素化する、より高レベルの抽象化レイヤーを使用することをお勧めします。

ManagedSecret および SecretRegistrar

ManagedSecret (Javadoc) API は、宣言型のシークレットライフサイクル管理を提供します。ManagedSecret は、SecretLeaseContainer に登録し、ユーザーに代わってリースイベントを処理する、より高レベルの抽象化です。SecretRegistrar (Javadoc) の実装として、レジストラビーンは AbstractVaultConfiguration を介して起動前にコンテナーに登録されます。

例 2: ManagedSecret の登録
@Configuration
class MyConfiguration {

  @Bean
  ManagedSecret mysqlCredentials(HikariDataSource dataSource) {
    return ManagedSecret.rotating("mysql/creds/my-role", secrets -> secrets.as(UsernamePassword::from)
          .applyTo((username, password) -> {
              connectionPool.setUsername(username);
              connectionPool.setPassword(password);
            }));
  }
}

マネージドシークレットを使用すると、シークレット管理とシークレットを使用するアプリケーションコンポーネントを直接接続できるため、シークレットがリクエストまたはローテーションされたときに、認証情報をアプリケーションコンポーネントに簡単に伝播できます。SecretLeaseContainers ライフサイクルでは、通常、コンテナーが起動してシークレットがリクエストされるまでシークレットの利用が延期されます。これは、InitializingBean.afterPropertiesSet() または @PostConstruct フェーズで認証情報を必要とするコンポーネントを使用する場合とは異なる場合があることに注意してください。AbstractVaultConfiguration では、Bean の作成中にコンテナーを意図的に起動して、早期に認証情報にアクセスできるようにします。いずれの場合も、コンポーネントの依存関係の順序を確認して、必要なときにシークレットが適切に初期化され、利用可能になるようにする必要があります。

TTL チューニング

リース更新とローテーションは TTL(Time To Live)の影響を受けるため、タイミングに直接関係します。SecretLeaseContainer は、リースが期限切れとみなされるかどうかを判断するために、有効期限しきい値(デフォルトは 1 分)を使用します。最小更新 TTL(デフォルトは 10 秒)は、短時間に連続して過剰な更新リクエストが発生するのを防ぎます。更新およびローテーション時間は、リース TTL の期間とローカルシステムクロック(具体的には TaskScheduler クロック)に基づいて計算されます。

リース期間満了判定のためのカスタム有効期限関数 Predicate<Lease> を設定できます。

トークン更新とセッション管理

Vault は、セッショントークンの有効期限が切れるか取り消された場合に、そのトークンに関連付けられたリースを取り消します。Vault セッションの有効期限が切れると (最大 TTL に達すると)、そのセッション内で発行されたリースもすべて取り消されます。SessionLeaseContainer は、SessionManager への登録のために AuthenticationListener から getAuthenticationListener() および getAuthenticationErrorListener() を提供し、再ログイン成功後に秘密裏に再起動できるようにします。

CertificateContainer

CertificateContainer は、Vault の PKI シークレットエンジンによって発行された証明書を管理します。証明書は通常リース契約に関連付けられていないため(実際、リース契約を避けることはパフォーマンス最適化の推奨事項です)、更新は不要ですが、有効期限が切れた際にローテーションすることができます。証明書のローテーションは、実質的に再発行に相当します。

Vault PKI は、複数の証明書型に対応しています。

  • X.509 証明書バンドル

    • TLS 暗号化

    • クライアント認証

  • X.509 証明書

    • トラストアンカー

このコンテナーは、起動および停止が可能な Spring Lifecycle コンポーネントであり、アプリケーション実行時に証明書を動的に管理できます。管理対象の証明書を表す RequestedCertificate (Javadoc) インスタンスを受け入れます。次のコード例は、CertificateContainer をセットアップしてイベントをリッスンする方法を示しています。

例 3: CertificateContainer の設定
CertificateContainer container = new CertificateContainer(vaultOperations.opsForPki());  (1)

RequestedCertificate cert = container
  .register(RequestedCertificate.trustAnchor("vault-ca"));                               (2)

RequestedCertificate bundle = RequestedCertificateBundle.issue("www.example.com",        (3)
      "testrole", VaultCertificateRequest.builder()
              .commonName("www.example.com")
              .ttl(Duration.ofHours(12)).build());

container.addCertificateListener(new CertificateListenerAdapter() {                      (4)
  @Override
  public void onCertificateEvent(CertificateEvent event) {
    if (cert.equals(event.getSource())) {
      if (event instanceof CertificateBundleIssuedEvent) {
        // Certificate bundle issued initially or rotated
      }
      if (event instanceof CertificateObtainedEvent) {
        // initial certificate obtained
      }
    }
  }
});

container.afterPropertiesSet();
container.start(); // events are triggered after starting the container
1VaultPkiOperations で初期化します。TaskScheduler が指定されていない場合、コンテナーはデフォルトのインスタンスを作成します。
2RequestedCertificate を介して発行者証明書をリクエストします (デフォルトまたは指定された発行者をサポートします)。
3 証明書リクエスト書とともに、RequestedCertificateBundle を通じて管理証明書バンドルをリクエストしてください。
4 証明書イベント用に CertificateListener を登録してください。登録順序が重要です。コンテナー起動後または証明書リクエスト後にリスナーを追加すると、初期のイベントを見逃す可能性があります。すべてのイベントをキャプチャーするには、コンテナー起動前にリスナーを設定してください。
CertificateContainer は、構成クラスが AbstractVaultConfiguration のサブクラスである場合に登録されます。これは通常、Spring Boot 以外のアプリケーションに適用されます。Spring Boot を使用する場合は、自動構成による登録を処理する Spring Cloud Vault [GitHub] (英語) を検討してください。

イベント

定期イベント

エラーイベント

CertificateContainer をリスナーと直接使用することで、証明書のライフサイクルとイベント処理をきめ細かく制御できます。しかし、一般的なアプリケーションシナリオでは、証明書の管理を簡素化する、より高レベルの抽象化レイヤーを使用することをお勧めします。

ManagedCertificate および CertificateRegistrar

ManagedCertificate (Javadoc) API は、宣言型の証明書ライフサイクル管理を提供します。ManagedCertificate は、CertificateContainer に登録し、証明書イベントをユーザーに代わって処理する、より高レベルの抽象化です。これは CertificateRegistrar (Javadoc) の実装です。レジストラ Bean は、コンテナー起動前に AbstractVaultConfiguration によって検出され、CertificateContainer に登録されます。

例 4: ManagedCertificate の登録
@Configuration
class MyConfiguration {

  @Bean
  ManagedCertificate serverCertificate(SslBundles bundles) {
    VaultCertificateRequest request = VaultCertificateRequest.builder()
            .commonName("www.example.com")
            .ttl(Duration.ofHours(12)).build();
    return ManagedCertificate.issue("my-bundle", "my-role", request, bundle -> {
      bundles.register("my-bundle", bundle.createKeyStore("my-alias"));
   });
  }
}

マネージド証明書を使用すると、証明書管理と証明書を使用するアプリケーションコンポーネントを直接接続できるため、アプリケーションコンポーネントへの資格情報の伝播が容易になります。CertificateContainer ライフサイクルでは、通常、コンテナーが起動して証明書がリクエストされるまで証明書の利用が延期されます。これは、InitializingBean.afterPropertiesSet() または @PostConstruct フェーズで資格情報を必要とするコンポーネントを使用する場合とは異なる場合があることに注意してください。AbstractVaultConfiguration では、Bean の作成時にコンテナーを意図的に起動して、早期に証明書にアクセスできるようにします。いずれの場合も、コンポーネントの依存関係の順序を確認し、必要なときに証明書が適切に初期化され、利用可能になるようにする必要があります。