Pengenalan Cepat untuk Konfigurasi Spring Cloud

1. Ikhtisar

Spring Cloud Config adalah pendekatan klien / server Spring untuk menyimpan dan melayani konfigurasi terdistribusi di berbagai aplikasi dan lingkungan.

Penyimpanan konfigurasi ini idealnya dibuat di bawah kontrol versi Git dan dapat dimodifikasi pada waktu proses aplikasi. Meskipun sangat cocok di aplikasi Spring menggunakan semua format file konfigurasi yang didukung bersama dengan konstruksi seperti Environment , PropertySource atau @Value , ini dapat digunakan di lingkungan apa pun yang menjalankan bahasa pemrograman apa pun.

Dalam artikel ini, kami akan fokus pada contoh cara menyiapkan server konfigurasi yang didukung Git , menggunakannya di server aplikasi REST sederhana dan menyiapkan lingkungan yang aman termasuk nilai properti terenkripsi.

2. Penyiapan dan Ketergantungan Proyek

Untuk bersiap menulis beberapa kode, kami membuat dua proyek Maven baru terlebih dahulu. Proyek server mengandalkan modul spring-cloud-config-server , serta paket spring-boot-starter-security dan spring-boot-starter-web starter:

 org.springframework.cloud spring-cloud-config-server   org.springframework.boot spring-boot-starter-security   org.springframework.boot spring-boot-starter-web 

Namun untuk proyek klien, kami hanya memerlukan modul spring-cloud-starter-config dan spring-boot-starter-web :

 org.springframework.cloud spring-cloud-starter-config   org.springframework.boot spring-boot-starter-web 

3. Implementasi Config Server

Bagian utama dari aplikasi ini adalah kelas konfigurasi - lebih khusus lagi @SpringBootApplication - yang menarik semua penyiapan yang diperlukan melalui anotasi konfigurasi otomatis @EnableConfigServer:

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

Sekarang kita perlu mengonfigurasi port server tempat server kita mendengarkan dan Git -url yang menyediakan konten konfigurasi yang dikontrol versi. Yang terakhir ini dapat digunakan dengan protokol seperti http , ssh atau file sederhana pada sistem file lokal.

Tip: Jika Anda berencana menggunakan beberapa contoh server konfigurasi yang mengarah ke repositori konfigurasi yang sama, Anda dapat mengonfigurasi server untuk menggandakan repo Anda ke folder sementara lokal. Tetapi waspadalah terhadap repositori pribadi dengan otentikasi dua faktor, mereka sulit ditangani! Dalam kasus seperti itu, lebih mudah untuk mengkloningnya di sistem file lokal Anda dan mengerjakan salinannya.

Ada juga beberapa variabel placeholder dan pola pencarian untuk mengonfigurasi repositori-url yang tersedia; tapi ini di luar cakupan artikel kami. Jika Anda tertarik, dokumentasi resmi adalah tempat yang baik untuk memulai.

Kita juga perlu mengatur nama pengguna dan kata sandi untuk Otentikasi-Dasar di properti application. kita untuk menghindari kata sandi yang dibuat secara otomatis pada setiap restart aplikasi:

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. Repositori Git sebagai Penyimpanan Konfigurasi

Untuk melengkapi server kita, kita harus menginisialisasi repositori Git di bawah url yang dikonfigurasi, membuat beberapa file properti baru dan mempopulerkannya dengan beberapa nilai.

Nama file konfigurasi disusun seperti properti aplikasi Spring biasa , tetapi alih-alih menggunakan kata 'application', nama yang dikonfigurasi, misalnya nilai properti 'spring.application.name' dari klien digunakan, diikuti dengan dasbor dan profil aktif. Sebagai contoh:

$> 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'

Pemecahan Masalah: Jika Anda mengalami masalah otentikasi terkait ssh , periksa kembali ~ / .ssh / known_hosts dan ~ / .ssh / authorized_keys di server ssh Anda!

5. Menanyakan Konfigurasi

Sekarang kami dapat memulai server kami. The Git -backed konfigurasi API yang disediakan oleh server kami dapat dilihat dengan menggunakan jalur berikut:

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

Di mana placeholder {label} merujuk ke cabang Git, {application} ke nama aplikasi klien dan {profile} ke profil aplikasi aktif klien saat ini.

Jadi kita dapat mengambil konfigurasi untuk klien konfigurasi yang direncanakan berjalan di bawah profil pengembangan di master cabang melalui:

$> curl //root:[email protected]:8888/config-client/development/master

6. Implementasi Klien

Selanjutnya, mari kita urus klien. Ini akan menjadi aplikasi klien yang sangat sederhana, terdiri dari pengontrol REST dengan satu metode GET .

Konfigurasi, untuk mengambil server kita, harus ditempatkan dalam file sumber daya bernama bootstrap.application , karena file ini (seperti namanya) akan dimuat sangat awal saat aplikasi dimulai:

@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); } }

Selain nama aplikasi, kami juga menempatkan profil aktif dan detail koneksi di bootstrap.properties kami :

spring.application.name=config-client spring.profiles.active=development spring.cloud.config.uri=//localhost:8888 spring.cloud.config.username=root spring.cloud.config.password=s3cr3t

Untuk mengujinya, jika konfigurasi diterima dengan benar dari server kami dan nilai peran dimasukkan ke dalam metode pengontrol kami, kami cukup menggulungnya setelah mem-boot klien:

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

Jika responsnya adalah sebagai berikut, Server Konfigurasi Cloud Spring kami dan kliennya berfungsi dengan baik untuk saat ini:

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

7. Enkripsi dan Dekripsi

Persyaratan : Untuk menggunakan kunci yang kuat secara kriptografis bersama dengan fitur enkripsi dan dekripsi Spring, Anda memerlukan 'File Kebijakan Yurisdiksi Kekuatan Tak Terbatas Java Cryptography Extension (JCE)' yang diinstal di JVM Anda . Ini dapat diunduh misalnya dari Oracle. Untuk menginstal ikuti instruksi yang disertakan dalam unduhan. Beberapa distribusi Linux juga menyediakan paket yang dapat diinstal melalui manajer paket mereka.

Karena server konfigurasi mendukung enkripsi dan dekripsi nilai properti, Anda dapat menggunakan repositori publik sebagai penyimpanan untuk data sensitif seperti nama pengguna dan sandi. Nilai terenkripsi diawali dengan string {cipher} dan dapat dihasilkan dengan panggilan REST ke jalur '/ encrypt' , jika server dikonfigurasi untuk menggunakan kunci simetris atau pasangan kunci.

Titik akhir untuk mendekripsi juga tersedia. Kedua endpoint menerima jalur yang berisi placeholder untuk nama aplikasi dan profilnya saat ini: '/ * / {name} / {profile}' . Ini sangat berguna untuk mengontrol kriptografi per klien. Namun, sebelum menjadi berguna, Anda harus mengkonfigurasi kunci kriptografi yang akan kita lakukan di bagian selanjutnya.

Tip: Jika Anda menggunakan curl untuk memanggil en- / decryption API, lebih baik gunakan opsi –data-urlencode (daripada –data / -d ), atau setel header 'Content-Type' secara eksplisit ke 'text / plain ' . Ini memastikan penanganan yang benar dari karakter khusus seperti '+' dalam nilai terenkripsi.

Jika nilai tidak dapat didekripsi secara otomatis saat diambil melalui klien, kuncinya akan diganti namanya dengan nama itu sendiri, diawali dengan kata 'tidak valid'. Ini harus mencegah, misalnya penggunaan nilai terenkripsi sebagai kata sandi.

Tip: Saat menyiapkan repositori yang berisi file YAML, Anda harus mengelilingi nilai terenkripsi dan prefiks Anda dengan tanda kutip tunggal! Dengan Properties ini tidak terjadi.

7.1. CSRF

Secara default, Spring Security mengaktifkan perlindungan CSRF untuk semua permintaan yang dikirim ke aplikasi kita.

Oleh karena itu, untuk dapat menggunakan titik akhir / encrypt dan / decrypt , mari kita nonaktifkan CSRF untuk mereka:

@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. Manajemen Kunci

Server konfigurasi secara default diaktifkan untuk mengenkripsi nilai properti secara simetris atau asimetris.

Untuk menggunakan kriptografi simetris , Anda hanya perlu menyetel properti 'encrypt.key' di application.properties menjadi rahasia pilihan Anda . Alternatifnya, Anda dapat memasukkan variabel lingkungan ENCRYPT_KEY .

For asymmetric cryptography, you can set ‘encrypt.key' to a PEM-encoded string value or configure a keystore to use.

Because we need a highly secured environment for our demo server, we chose the latter option and generating a new keystore, including a RSA key-pair, with the Java keytool first:

$> 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

After that, we're adding the created keystore to our server's bootstrap.properties and re-run it:

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

As next step we can query the encryption-endpoint and add the response as value to a configuration in our repository:

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

To test, if our setup works correctly, we're modifying the ConfigClient class and restart our client:

@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); } }

A final query against our client will show us, if our configuration value is being correct decrypted:

$> curl //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. Using Multiple Keys

If you want to use multiple keys for encryption and decryption, for example: a dedicated one for each served application, you can add another prefix in the form of {name:value} between the {cipher} prefix and the BASE64-encoded property value.

The config server understands prefixes like {secret:my-crypto-secret} or {key:my-key-alias} nearly out-of-the-box. The latter option needs a configured keystore in your application.properties. This keystore is searched for a matching key alias. For example:

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

For scenarios without keystore you have to implement a @Bean of type TextEncryptorLocator which handles the lookup and returns a TextEncryptor-Object for each key.

7.4. Serving Encrypted Properties

If you want to disable server-side cryptography and handle decryption of property-values locally, you can put the following in your server's application.properties:

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

Furthermore you can delete all the other ‘encrypt.*' properties to disable the REST endpoints.

8. Conclusion

Now we are able to create a configuration server to provide a set of configuration files from a Git repository to client applications. There are a few other things you can do with such a server.

For example:

  • Serve configuration in YAML or Properties format instead of JSON – also with placeholders resolved. Which can be useful, when using it in non-Spring environments, where the configuration is not directly mapped to a PropertySource.
  • Serve plain text configuration files – in turn optionally with resolved placeholders. This can be useful for example to provide an environment-dependent logging-configuration.
  • Embed the config server into an application, where it configures itself from a Git repository, instead of running as standalone application serving clients. Therefore some bootstrap properties must be set and/or the @EnableConfigServer annotation must be removed, which depends on the use case.
  • Buat server konfigurasi tersedia di penemuan layanan Spring Netflix Eureka dan aktifkan penemuan server otomatis di klien konfigurasi. Ini menjadi penting jika server tidak memiliki lokasi tetap atau berpindah di lokasinya.

Dan sebagai penutup, Anda akan menemukan kode sumber untuk artikel ini di Github .