1. 概要

Spring Cloud Config は、複数のアプリケーションと環境に分散した構成を保存および提供するためのSpringのクライアント/サーバーアプローチです。

この構成ストアは、理想的には Git バージョン管理の下でバージョン管理され、アプリケーションの実行時に変更できます。 サポートされているすべての構成ファイル形式とEnvironment PropertySource、@ Value などの構成を使用するSpringアプリケーションに非常によく適合しますが、プログラミング言語。

このチュートリアルでは、 Git でバックアップされた構成サーバーをセットアップし、それを単純な REST アプリケーションサーバーで使用し、暗号化されたプロパティを含む安全な環境をセットアップする方法に焦点を当てます。値。

2. プロジェクトの設定と依存関係

まず、2つの新しいMavenプロジェクトを作成します。 サーバープロジェクトは、 spring-cloud-config-server モジュール、およびspring-boot-starter-securityspring-boot-starter-webに依存しています。 スターターバンドル:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

ただし、クライアントプロジェクトの場合、必要なのは spring-cloud-starter-configspring-boot-starter-webモジュールのみです。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3. 構成サーバーの実装

アプリケーションの主要部分は構成クラス、より具体的には @SpringBootApplication であり、 auto-configureアノテーション@EnableConfigServer:を介して必要なすべてのセットアップを取り込みます。 ]

@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
    
    public static void main(String[] arguments) {
        SpringApplication.run(ConfigServer.class, arguments);
    }
}

次に、サーバーがリッスンしているサーバー port と、バージョン管理された構成コンテンツを提供する Git-urlを構成する必要があります。 後者は、 http ssh、、またはローカルファイルシステム上の単純なファイルなどのプロトコルで使用できます。

ヒント:同じ構成リポジトリを指す複数の構成サーバーインスタンスを使用することを計画している場合は、リポジトリをローカルの一時フォルダーに複製するようにサーバーを構成できます。 ただし、2要素認証を使用するプライベートリポジトリに注意してください。 扱いにくいです! このような場合、ローカルファイルシステムにクローンを作成してコピーを操作する方が簡単です。

利用可能なrepository-urlを構成するためのプレースホルダー変数と検索パターンもいくつかあります。 ただし、これはこの記事の範囲を超えています。  詳細を知りたい場合は、公式ドキュメントから始めることをお勧めします。

また、application.propertiesBasic-Authenticationのユーザー名とパスワードを設定して、アプリケーションを再起動するたびにパスワードが自動生成されないようにする必要があります。

server.port=8888
spring.cloud.config.server.git.uri=ssh://localhost/config-repo
spring.cloud.config.server.git.clone-on-start=true
spring.security.user.name=root
spring.security.user.password=s3cr3t

4. 構成ストレージとしてのGitリポジトリ

サーバーを完成させるには、構成されたURLで Git リポジトリを初期化し、いくつかの新しいプロパティファイルを作成し、それらにいくつかの値を入力する必要があります。

構成ファイルの名前は、通常のSpring application.properties のように構成されますが、「application」という単語の代わりに、プロパティの値などの構成された名前‘[X198Xクライアントの].application.name’、が使用され、その後にダッシュとアクティブなプロファイルが続きます。 例えば:

$> git init
$> echo 'user.role=Developer' > config-client-development.properties
$> echo 'user.role=User'      > config-client-production.properties
$> git add .
$> git commit -m 'Initial config-client properties'

トラブルシューティング: ssh 関連の認証の問題が発生した場合は、〜/ .ssh / known_hosts〜/ .ssh/authorized_keysを再確認できます。 sshサーバー上の

5. 構成の照会

これで、サーバーを起動できます。 サーバーが提供するGitベースの構成APIは、次のパスを使用してクエリできます。

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

{label} プレースホルダーはGitブランチを参照し、 {application} はクライアントのアプリケーション名を参照し、{profile}はクライアントの現在アクティブなアプリケーションプロファイルを参照します。

したがって、次の方法で、ブランチmasterの開発プロファイルで実行されている計画済み構成クライアントの構成を取得できます。

$> curl http://root:s3cr3t@localhost:8888/config-client/development/master

6. クライアントの実装

次に、クライアントの世話をしましょう。 これは非常に単純なクライアントアプリケーションであり、RESTコントローラーと1つのGETメソッドで構成されます。

サーバーをフェッチするには、構成をapplication.propertiesファイルに配置する必要があります。 Spring Boot 2.4では、 spring .config.import プロパティを使用して構成データをロードする新しい方法が導入されました。これは、構成サーバーにバインドするデフォルトの方法です。

@SpringBootApplication
@RestController
public class ConfigClient {
    
    @Value("${user.role}")
    private String role;

    public static void main(String[] args) {
        SpringApplication.run(ConfigClient.class, args);
    }

    @GetMapping(
      value = "/whoami/{username}",  
      produces = MediaType.TEXT_PLAIN_VALUE)
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello! 
          You're %s and you'll become a(n) %s...\n", username, role);
    }
}

アプリケーション名に加えて、アクティブなプロファイルと接続の詳細もapplication.propertiesに配置します。

spring.application.name=config-client
spring.profiles.active=development
spring.config.import=optional:configserver:http://root:s3cr3t@localhost:8888

これにより、http:// localhost:8888のConfig Serverに接続され、接続の開始時にHTTP基本セキュリティも使用されます。 ユーザー名とパスワードを別々に設定することもできます spring.cloud.config.usernamespring.cloud.config.password それぞれプロパティ。

場合によっては、サービスがConfig Serverに接続できない場合、サービスの起動に失敗したいことがあります。 これが望ましい動作である場合は、オプションのプレフィックスを削除して、クライアントを例外で停止させることができます。

サーバーから構成が正しく受信され、ロール値がコントローラーメソッドに挿入されるかどうかをテストするには、クライアントの起動後にカールします。

$> curl http://localhost:8080/whoami/Mr_Pink

応答が次の場合、 Spring Cloud ConfigServerとそのクライアントは現在正常に動作しています。

Hello! You're Mr_Pink and you'll become a(n) Developer...

7. 暗号化と復号化

要件 :Spring暗号化および復号化機能と一緒に暗号的に強力なキーを使用するには、 「Java暗号化拡張機能(JCE)無制限の強度管轄ポリシーファイル」 私たちにインストールされています JVM。 これらは、たとえば、からダウンロードできます。 オラクル 。 インストールするには、ダウンロードに含まれている手順に従ってください。 一部のLinuxディストリビューションでは、パッケージマネージャーを介してインストール可能なパッケージも提供されています。

構成サーバーはプロパティ値の暗号化と復号化をサポートしているため、ユーザー名やパスワードなどの機密データのストレージとしてパブリックリポジトリを使用できます。 暗号化された値の前には文字列{cipher}、が付いており、サーバーが対称鍵またはキーペア。

復号化するエンドポイントも利用できます。 両方のエンドポイントは、アプリケーションの名前とその現在のプロファイルのプレースホルダーを含むパスを受け入れます:‘/ * / {name} / {profile}’。これは、クライアントごとの暗号化を制御する場合に特に便利です。 ただし、それらが役立つ前に、暗号化キーを構成する必要があります。これについては、次のセクションで行います。

ヒント:curlを使用してen-/decryption APIを呼び出す場合は、 –data / -d [X140Xの代わりに–data-urlencodeオプションを使用することをお勧めします])、または’Content-Type’ヘッダーを‘text /plain’に明示的に設定します。 これにより、暗号化された値の「+」などの特殊文字が正しく処理されます。

クライアントを介したフェッチ中に値を自動的に復号化できない場合、その key は、名前自体に名前が変更され、接頭辞として「invalid」が付けられます。 これにより、暗号化された値がパスワードとして使用されるのを防ぐことができます。

ヒント: YAMLファイルを含むリポジトリを設定するときは、暗号化されてプレフィックスが付けられた値を一重引用符で囲む必要があります。 ただし、これはプロパティには当てはまりません。

7.1. CSRF

デフォルトでは、Springセキュリティは、アプリケーションに送信されるすべてのリクエストに対してCSRF保護を有効にします。

したがって、 /cryptoおよび/decode エンドポイントを使用できるようにするには、それらのCSRFを無効にしましょう。

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf()
          .ignoringAntMatchers("/encrypt/**")
          .ignoringAntMatchers("/decrypt/**");

        super.configure(http);
    }
}

7.2. キー管理

デフォルトでは、構成サーバーは対称または非対称の方法でプロパティ値を暗号化できます。

対称暗号を使用するには 、プロパティを設定するだけです ‘encrypt.key’ 私たちの中で application.properties 私たちの選択の秘密に 。 または、環境変数を渡すこともできます ENCRYPT_KEY

非対称暗号化の場合、‘encrypt.key’PEM でエンコードされた文字列値に設定するか、keystoreを使用するように構成できます。

デモサーバーには高度にセキュリティ保護された環境が必要なため、後者のオプションを選択し、RSAキーペアを含む新しいキーストアをJavakeytool最初:

$> keytool -genkeypair -alias config-server-key \
       -keyalg RSA -keysize 4096 -sigalg SHA512withRSA \
       -dname 'CN=Config Server,OU=Spring Cloud,O=Baeldung' \
       -keypass my-k34-s3cr3t -keystore config-server.jks \
       -storepass my-s70r3-s3cr3t

次に、作成したキーストアをサーバーのアプリケーション .properties に追加し、再実行します。

encrypt.keyStore.location=classpath:/config-server.jks
encrypt.keyStore.password=my-s70r3-s3cr3t
encrypt.keyStore.alias=config-server-key
encrypt.keyStore.secret=my-k34-s3cr3t

次に、暗号化エンドポイントをクエリし、リポジトリ内の構成に値として応答を追加します。

$> export PASSWORD=$(curl -X POST --data-urlencode d3v3L \
       http://root:s3cr3t@localhost:8888/encrypt)
$> echo "user.password={cipher}$PASSWORD" >> config-client-development.properties
$> git commit -am 'Added encrypted password'
$> curl -X POST http://root:s3cr3t@localhost:8888/refresh

セットアップが正しく機能するかどうかをテストするために、 ConfigClient クラスを変更して、クライアントを再起動します。

@SpringBootApplication
@RestController
public class ConfigClient {

    ...
    
    @Value("${user.password}")
    private String password;

    ...
    public String whoami(@PathVariable("username") String username) {
        return String.format("Hello! 
          You're %s and you'll become a(n) %s, " +
          "but only if your password is '%s'!\n", 
          username, role, password);
    }
}

最後に、クライアントに対するクエリは、構成値が正しく復号化されているかどうかを示します。

$> curl http://localhost:8080/whoami/Mr_Pink
Hello! You're Mr_Pink and you'll become a(n) Developer, \
  but only if your password is 'd3v3L'!

7.3. 複数のキーの使用

提供されるアプリケーションごとに専用のキーなど、暗号化と復号化に複数のキーを使用する場合は、{cipher}の間に{name:value}の形式で別のプレフィックスを追加できます。 プレフィックスとBASE64でエンコードされたプロパティ値。

構成サーバーは、 {secret:my-crypto-secret}{key:my-key-alias}などのプレフィックスをほとんどすぐに理解できます。 後者のオプションでは、application.propertiesにキーストアを構成する必要があります。 このキーストアで、一致するキーエイリアスが検索されます。 例:

user.password={cipher}{secret:my-499-s3cr3t}AgAMirj1DkQC0WjRv...
user.password={cipher}{key:config-client-key}AgAMirj1DkQC0WjRv...

キーストアのないシナリオでは、タイプ TextEncryptorLocator、 @ Bean を実装する必要があります。これは、ルックアップを処理し、各キーのTextEncryptor-Objectを返します。

7.4. 暗号化されたプロパティの提供

サーバー側の暗号化を無効にし、プロパティ値の復号化をローカルで処理する場合は、サーバーのapplication.propertiesに次のように配置できます。

spring.cloud.config.server.encrypt.enabled=false

さらに、他のすべての「encrypt。*」プロパティを削除して、RESTエンドポイントを無効にすることができます。

8. 結論

これで、構成サーバーを作成して、Gitリポジトリからクライアントアプリケーションに構成ファイルのセットを提供できるようになりました。 このようなサーバーでできることは他にもいくつかあります。

例えば:

  • JSONの代わりにYAMLまたはProperties形式で構成を提供し、もプレースホルダーを解決します。 これは、構成がPropertySourceに直接マップされていない非Spring環境で使用する場合に役立ちます。
  • プレーンテキストの構成ファイルを順番に提供します。オプションで、解決されたプレースホルダーを使用します。 たとえば、これは環境に依存するロギング構成を提供するのに役立ちます。
  • 構成サーバーをアプリケーションに埋め込みます。アプリケーションは、クライアントにサービスを提供するスタンドアロンアプリケーションとして実行するのではなく、Gitリポジトリから構成します。 したがって、いくつかのプロパティを設定するか、@EnableConfigServerアノテーションを削除する必要があります。これはユースケースによって異なります。
  • Spring Netflix Eurekaサービスディスカバリで構成サーバーを利用できるようにし、構成クライアントで自動サーバー検出を有効にします。 これは、サーバーに固定の場所がない場合、またはサーバーがその場所に移動する場合に重要になります。

いつものように、この記事のソースコードはGithubから入手できます。