今回も引き続き、Key Vaultを作成しKey Vaultのシークレットを取得する処理の実装について述べる。ここでは、具体的なサンプルプログラムのソースコードを共有する。
前提条件
下記記事のKeyVaultの作成が完了していること。
作成したサンプルプログラム(App Service側)の内容
作成したサンプルプログラム(App Service側)の構成は以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
pom.xmlの内容は以下の通りで、Key Vaultのライブラリの設定を追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demoAzureApp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>demoAzureApp</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- lombokの設定 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- Key Vaultの設定 --> <dependency> <groupId>com.azure</groupId> <artifactId>azure-security-keyvault-secrets</artifactId> <version>4.2.3</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-identity</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure</artifactId> <version>1.36.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-webapp-maven-plugin</artifactId> <version>1.12.0</version> <configuration> <schemaVersion>v2</schemaVersion> <subscriptionId>(ログインユーザーのサブスクリプションID)</subscriptionId> <resourceGroup>azureAppDemo</resourceGroup> <appName>azureAppDemoService</appName> <pricingTier>B1</pricingTier> <region>japaneast</region> <appServicePlanName>ASP-azureAppDemo-8679</appServicePlanName> <appServicePlanResourceGroup>azureAppDemo</appServicePlanResourceGroup> <runtime> <os>Linux</os> <javaVersion>Java 8</javaVersion> <webContainer>Tomcat 8.5</webContainer> </runtime> <deployment> <resources> <resource> <directory>${project.basedir}/target</directory> <includes> <include>*.war</include> </includes> </resource> </resources> </deployment> </configuration> </plugin> </plugins> </build> </project> |
また、application.propertiesの内容は以下の通りで、サービスプリンシパルを利用してKey Vaultにアクセスするための設定を追加している。
1 2 3 4 5 6 7 8 9 10 | server.port = 8084 demoAzureFunc.urlBase = http://localhost:7071/api/ #demoAzureFunc.urlBase = https://azurefuncdemoapp.azurewebsites.net/api/ # Key Vaultへの設定 keyVaultClientId=cdbb5434-e455-4885-b2e6-911f78c4264b keyVaultTenantId=f6a12dea-7649-441f-9e63-bc9e254b2500 keyVaultClientKey=(サービスプリンシパルのパスワード) keyVaultUri=https://keypurinit.vault.azure.net/ keyVaultSecretKey=keySecret |
なお、上記設定のkeyVaultClientId、keyVaultTenantId、keyVaultClientKey、keyVaultUriは、以下のサービスプリンシパル作成時のコマンド実行時に出力されたappId、tenant、password、nameの値を指定している。
また、keyVaultSecretKeyは、以下の画面のシークレットのキー値を指定している。
コントローラクラスの内容は以下の通りで、後述するAzure Functions側のgetKeySecret関数を呼び出す処理と、KeyVaultからシークレットを取得する処理を追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.credentials.ApplicationTokenCredentials; import com.microsoft.azure.keyvault.KeyVaultClient; import com.microsoft.azure.keyvault.models.SecretBundle; @Controller public class DemoController { /** RestTemplateオブジェクト */ @Autowired private RestTemplate restTemplate; /** ObjectMapperオブジェクト */ @Autowired private ObjectMapper objectMapper; /** application.propertiesからdemoAzureFunc.urlBaseの値を取得 */ @Value("${demoAzureFunc.urlBase}") private String demoAzureFuncBase; /** keyVaultのクライアントID */ @Value("${keyVaultClientId}") private String keyVaultClientId; /** keyVaultのテナントID */ @Value("${keyVaultTenantId}") private String keyVaultTenantId; /** keyVaultのクライアントキー */ @Value("${keyVaultClientKey}") private String keyVaultClientKey; /** keyVaultのURI */ @Value("${keyVaultUri}") private String keyVaultUri; /** keyVaultのシークレットのキー */ @Value("${keyVaultSecretKey}") private String keyVaultSecretKey; @GetMapping("/") public String index(Model model) { // Azure FunctionsのgetKeySecret関数を呼び出すためのヘッダー情報を設定する HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); // Azure FunctionsのgetKeySecret関数を呼び出すための引数を設定する MultiValueMap<String, String> map = new LinkedMultiValueMap<>(); try { map.add("key", "keySecret"); } catch (Exception ex) { throw new RuntimeException(ex); } HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(map, headers); // Azure FunctionsのgetKeySecret関数を呼び出す ResponseEntity<String> response = restTemplate.exchange(demoAzureFuncBase + "getKeySecret", HttpMethod.POST, entity, String.class); // Azure Functionsの呼出結果のシークレットを、Modelオブジェクトに設定する try { GetKeySecretResult getKeySecretResult = objectMapper.readValue( response.getBody(), GetKeySecretResult.class); model.addAttribute("keySecretFunctions", getKeySecretResult.getSecret()); } catch (Exception ex) { throw new RuntimeException(ex); } // Azure App Serviceでのシークレットを、Modelオブジェクトに設定する model.addAttribute("keySecretAppService", getKeySecret()); return "index"; } /** * KeyVaultからシークレットを取得する * * @return シークレット値 */ private String getKeySecret() { ApplicationTokenCredentials credentials = new ApplicationTokenCredentials(keyVaultClientId , keyVaultTenantId, keyVaultClientKey, AzureEnvironment.AZURE); KeyVaultClient keyVaultClient = new KeyVaultClient(credentials); SecretBundle bundle = keyVaultClient.getSecret(keyVaultUri, keyVaultSecretKey); return bundle.value(); } } |
また、Azure Functions側のgetKeySecret関数を呼び出した結果を格納するクラスは、以下の通り。
1 2 3 4 5 6 7 8 9 10 11 | package com.example.demo; import lombok.Data; @Data public class GetKeySecretResult { /** シークレットの値 */ private String secret; } |
さらに、コンフィグクラスの内容は以下の通りで、コントローラクラスで呼び出すBean定義を行っている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.example.demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.ObjectMapper; @Configuration public class DemoConfigBean { /** * RestTemplateオブジェクトを作成する * @return RestTemplateオブジェクト */ @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } /** * ObjectMapperオブジェクトを作成する * @return ObjectMapperオブジェクト */ @Bean public ObjectMapper getObjectMapper() { return new ObjectMapper(); } } |
また、HTMLファイルの内容は以下の通りで、取得したシークレットの値を表示するようにしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!DOCTYPE html> <html lang="ja" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>初期表示画面</title> </head> <body> Azure App Serviceで取得したシークレット: <span th:text="${keySecretAppService}">keySecretAppService</span><br/><br/> Azure Functionsで取得したシークレット: <span th:text="${keySecretFunctions}">keySecretFunctions</span> </body> </html> |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/azure/tree/master/azure-key-vault-2/demoAzureApp
作成したサンプルプログラム(Azure Functions側)の内容
作成したサンプルプログラム(Azure Functions側)の構成は以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加・変更したプログラムである。
<2021年4月13日 追記>
spring-cloud-function-dependenciesのバージョンは、2021年3月16日にリリースしたバージョン3.1.2を利用すると、1つのAzure Functions内に複数のファンクションを含む場合の不具合が解消できている。
その場合、Handlerクラスの継承するクラスを「AzureSpringBootRequestHandler」クラスから「FunctionInvoker」クラスに変更する。
spring-cloud-function-dependenciesの3.1.2を利用した実装サンプルは、以下の記事を参照のこと。
pom.xmlの内容は以下の通りで、App Service側と同様に、Key Vaultのライブラリの設定を追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demoAzureFunc</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Hello Spring Function on Azure</name> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <azure.functions.maven.plugin.version>1.9.0</azure.functions.maven.plugin.version> <!-- customize those properties. The functionAppName should be unique across Azure --> <functionResourceGroup>azureAppDemo</functionResourceGroup> <functionAppName>azureFuncDemoApp</functionAppName> <functionAppServicePlan>ASP-azureAppDemo-8679</functionAppServicePlan> <functionPricingTier>B1</functionPricingTier> <functionAppRegion>japaneast</functionAppRegion> <stagingDirectory>${project.build.directory}/azure-functions/${functionAppName}</stagingDirectory> <start-class>com.example.DemoAzureFunction</start-class> <spring.boot.wrapper.version>1.0.25.RELEASE</spring.boot.wrapper.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-function-adapter-azure</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-function-web</artifactId> <scope>provided</scope> </dependency> <!-- Spring Boot Webの設定 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- lombokを利用するための設定 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- Key Vaultの設定 --> <dependency> <groupId>com.azure</groupId> <artifactId>azure-security-keyvault-secrets</artifactId> <version>4.2.3</version> </dependency> <dependency> <groupId>com.azure</groupId> <artifactId>azure-identity</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.microsoft.azure</groupId> <artifactId>azure</artifactId> <version>1.36.3</version> </dependency> <!-- Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-function-dependencies</artifactId> <version>2.0.1.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <pluginManagement> <plugins> <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-functions-maven-plugin</artifactId> <version>${azure.functions.maven.plugin.version}</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.1.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> </plugins> </pluginManagement> <plugins> <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-functions-maven-plugin</artifactId> <configuration> <resourceGroup>${functionResourceGroup}</resourceGroup> <appName>${functionAppName}</appName> <appServicePlanName>${functionAppServicePlan}</appServicePlanName> <region>${functionAppRegion}</region> <pricingTier>${functionPricingTier}</pricingTier> <runtime> <os>Linux</os> <javaVersion>8</javaVersion> </runtime> <appSettings> <!-- Run Azure Function from package file by default --> <property> <name>WEBSITE_RUN_FROM_PACKAGE</name> <value>1</value> </property> <property> <name>FUNCTIONS_EXTENSION_VERSION</name> <value>~3</value> </property> <property> <name>FUNCTIONS_WORKER_RUNTIME</name> <value>java</value> </property> </appSettings> </configuration> <executions> <execution> <id>package-functions</id> <goals> <goal>package</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <executions> <execution> <id>copy-resources</id> <phase>package</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <overwrite>true</overwrite> <outputDirectory> ${project.build.directory}/azure-functions/${functionAppName} </outputDirectory> <resources> <resource> <directory>${project.basedir}/src/main/azure </directory> <includes> <include>**</include> </includes> </resource> </resources> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>copy-dependencies</id> <phase>prepare-package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${stagingDirectory}/lib</outputDirectory> <overWriteReleases>false</overWriteReleases> <overWriteSnapshots>false</overWriteSnapshots> <overWriteIfNewer>true</overWriteIfNewer> <includeScope>runtime</includeScope> </configuration> </execution> </executions> </plugin> <!--Remove obj folder generated by .NET SDK in maven clean--> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> <configuration> <filesets> <fileset> <directory>obj</directory> </fileset> </filesets> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot.experimental</groupId> <artifactId>spring-boot-thin-layout</artifactId> <version>${spring.boot.wrapper.version}</version> </dependency> </dependencies> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/libs-snapshot-local</url> <snapshots> <enabled>true</enabled> </snapshots> <releases> <enabled>false</enabled> </releases> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone-local</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/release</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/libs-snapshot-local</url> <snapshots> <enabled>true</enabled> </snapshots> <releases> <enabled>false</enabled> </releases> </pluginRepository> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/libs-milestone-local</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-releases</id> <name>Spring Releases</name> <url>https://repo.spring.io/libs-release-local</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> </pluginRepositories> </project> |
application.propertiesの内容は以下の通りで、App Service側と同様に、サービスプリンシパルを利用してKey Vaultにアクセスするための設定を追加している。
1 2 3 4 5 6 | # Key Vaultへの設定 keyVaultClientId=cdbb5434-e455-4885-b2e6-911f78c4264b keyVaultTenantId=f6a12dea-7649-441f-9e63-bc9e254b2500 keyVaultClientKey=(サービスプリンシパルのパスワード) keyVaultUri=https://keypurinit.vault.azure.net/ keyVaultSecretKey=keySecret |
サービスクラスの内容は以下の通りで、App Service側と同様に、KeyVaultからシークレットを取得する処理を追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | package com.example.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.example.model.GetKeySecretForm; import com.example.model.GetKeySecretResult; import com.microsoft.azure.AzureEnvironment; import com.microsoft.azure.credentials.ApplicationTokenCredentials; import com.microsoft.azure.keyvault.KeyVaultClient; import com.microsoft.azure.keyvault.models.SecretBundle; @Service public class GetKeySecretService { /** keyVaultのクライアントID */ @Value("${keyVaultClientId}") private String keyVaultClientId; /** keyVaultのテナントID */ @Value("${keyVaultTenantId}") private String keyVaultTenantId; /** keyVaultのクライアントキー */ @Value("${keyVaultClientKey}") private String keyVaultClientKey; /** keyVaultのURI */ @Value("${keyVaultUri}") private String keyVaultUri; /** keyVaultのシークレットのキー */ @Value("${keyVaultSecretKey}") private String keyVaultSecretKey; /** * 検索用Formに設定したキーにあてはまるシークレットを取得する * * @param getKeySecretForm 検索用Form * @return 結果情報オブジェクト */ public GetKeySecretResult getKeySecret(GetKeySecretForm getKeySecretForm) { GetKeySecretResult getKeySecretResult = new GetKeySecretResult(); if (keyVaultSecretKey.equals(getKeySecretForm.getKey())) { // KeyVaultからシークレットを取得し設定する getKeySecretResult.setSecret(getKeySecret()); } return getKeySecretResult; } /** * KeyVaultからシークレットを取得する * * @return シークレット値 */ private String getKeySecret() { ApplicationTokenCredentials credentials = new ApplicationTokenCredentials(keyVaultClientId , keyVaultTenantId, keyVaultClientKey, AzureEnvironment.AZURE); KeyVaultClient keyVaultClient = new KeyVaultClient(credentials); SecretBundle bundle = keyVaultClient.getSecret(keyVaultUri, keyVaultSecretKey); return bundle.value(); } } |
ハンドラークラスの内容は以下の通りで、Azure App Serviceのコントローラクラスから呼ばれるgetKeySecret関数である。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package com.example; import java.util.Optional; import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHandler; import com.example.model.GetKeySecretForm; import com.example.model.GetKeySecretResult; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; import com.microsoft.azure.functions.HttpRequestMessage; import com.microsoft.azure.functions.HttpResponseMessage; import com.microsoft.azure.functions.HttpStatus; import com.microsoft.azure.functions.annotation.AuthorizationLevel; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; public class GetKeySecretHandler extends AzureSpringBootRequestHandler<GetKeySecretForm, GetKeySecretResult> { /** * HTTP要求に応じて、DemoAzureFunctionクラスのgetKeySecretメソッドを呼び出し、 * その戻り値をボディに設定したレスポンスを返す * @param request リクエストオブジェクト * @param context コンテキストオブジェクト * @return レスポンスオブジェクト */ @FunctionName("getKeySecret") public HttpResponseMessage execute( @HttpTrigger(name = "request" , methods = HttpMethod.POST, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, ExecutionContext context) { // リクエストオブジェクトからパラメータ値を取得し、検索用Formに設定する ObjectMapper mapper = new ObjectMapper(); String jsonParam = request.getBody().get(); jsonParam = jsonParam.replaceAll("\\[", "").replaceAll("\\]", ""); GetKeySecretForm getKeySecretForm = new GetKeySecretForm(); try { getKeySecretForm = mapper.readValue(jsonParam , new TypeReference<GetKeySecretForm>() { }); } catch (Exception ex) { throw new RuntimeException(ex); } // handleRequestメソッド内でDemoAzureFunctionクラスのgetKeySecretメソッド // を呼び出し、その戻り値をボディに設定したレスポンスを、JSON形式で返す return request.createResponseBuilder(HttpStatus.OK) .body(handleRequest(getKeySecretForm, context)) .header("Content-Type", "text/json").build(); } } |
また、Azure Functionsのメインクラスは以下の通りで、前述のサービスクラスを呼び出していて、先ほどのハンドラークラスのhandleRequestメソッドで呼び出される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package com.example; import java.util.function.Function; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import com.example.model.GetKeySecretForm; import com.example.model.GetKeySecretResult; import com.example.service.GetKeySecretService; @SpringBootApplication public class DemoAzureFunction { /** シークレット取得サービスクラスのオブジェクト */ @Autowired private GetKeySecretService getKeySecretService; public static void main(String[] args) throws Exception { SpringApplication.run(DemoAzureFunction.class, args); } /** * キーに対応するシークレットを取得し結果を返却する関数 * * @return シークレット取得サービスクラスの呼出結果 */ @Bean public Function<GetKeySecretForm, GetKeySecretResult> getKeySecret() { return getKeySecretForm -> getKeySecretService.getKeySecret(getKeySecretForm); } } |
さらに、Azure FunctionsのメインクラスのgetKeySecretメソッドの引数・戻り値は以下のクラスで定義している。
1 2 3 4 5 6 7 8 9 10 11 | package com.example.model; import lombok.Data; @Data public class GetKeySecretForm { /** キーの値 */ private String key; } |
1 2 3 4 5 6 7 8 9 10 11 | package com.example.model; import lombok.Data; @Data public class GetKeySecretResult { /** シークレットの値 */ private String secret; } |
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/azure/tree/master/azure-key-vault-2/demoAzureFunc
要点まとめ
- プログラム上でKeyVaultのシークレットを取得するには、pom.xmlにKey Vaultにアクセスするためのライブラリを追加し、application.propertiesにサービスプリンシパルの設定値を追加し、KeyVaultClientクラスを使ってシークレットの取得を行えばよい。