Azure / azure-sdk-for-java

This repository is for active development of the Azure SDK for Java. For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/java/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-java.
MIT License
2.3k stars 1.96k forks source link

[BUG] azure-spring-boot-starter-keyvault-certificates can't work in Azure Contanier apps using Managed Identity #32280

Open backwind1233 opened 1 year ago

backwind1233 commented 1 year ago

Describe the bug Applications dependend on azure-spring-boot-starter-keyvault-certificates can't work in Azure Contanier apps using Managed Identity.

Following this doc Tutorial: Secure Spring Boot apps using Azure Key Vault certificates but using in a container app.

This is the error I got when using

        <dependency>
            <groupId>com.azure.spring</groupId>
            <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
            <version>3.14.0</version>
        </dependency>

Exception or Stack Trace

" :: Spring Boot ::                (v2.7.5)"

"2022-11-17 05:01:59.876  INFO 1 --- [           main] com.example.ssltest.SsltestApplication   : Starting SsltestApplication v0.0.1-SNAPSHOT using Java 11.0.16.1 on myspringapp--zcy432h-79f66559db-2lpxh with PID 1 (/opt/app/app.jar started by root in /opt/app)"
"2022-11-17 05:01:59.879  INFO 1 --- [           main] com.example.ssltest.SsltestApplication   : No active profile set, falling back to 1 default profile: ""default"""
"2022-11-17 05:02:11.273  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8443 (https)"
"2022-11-17 05:02:11.283  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]"
"2022-11-17 05:02:11.371  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]"
"2022-11-17 05:02:11.776  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext"
"2022-11-17 05:02:11.777  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 11495 ms"
"2022-11-17 05:02:24.286  INFO 1 --- [           main] c.a.s.k.j.implementation.KeyVaultClient  : Using Azure Key Vault: https://robngonkeyvault.vault.azure.net/"
"2022-11-17 05:02:24.373  INFO 1 --- [           main] c.a.s.k.j.i.utils.AccessTokenUtil        : Getting access token using managed identity"
"2022-11-17 05:02:21.278  INFO 1 --- [           main] c.a.c.i.jackson.JacksonVersion           : Package versions: jackson-core=2.13.4, jackson-databind=2.13.4-2, jackson-dataformat-xml=2.13.4, jackson-datatype-jsr310=2.13.4, azure-core=1.32.0, Troubleshooting version conflicts: https://aka.ms/azsdk/java/dependency/troubleshoot"
"2022-11-17 05:02:21.778  INFO 1 --- [           main] AbstractAzureServiceClientBuilderFactory : Will configure the default credential of type DefaultAzureCredential for class com.azure.identity.DefaultAzureCredentialBuilder."
"2022-11-17 05:04:35.526  WARN 1 --- [           main] c.a.s.k.j.implementation.utils.HttpUtil  : Unable to finish the http get request."

"com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.conn.HttpHostConnectException: Connect to 169.254.169.254:80 [/169.254.169.254] failed: Connection timed out (Connection timed out)"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:156) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:221) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.shaded.org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.utils.HttpUtil.get(HttpUtil.java:62) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil.getAccessTokenOnOthers(AccessTokenUtil.java:171) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil.getAccessToken(AccessTokenUtil.java:72) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.KeyVaultClient.getAccessTokenByHttpRequest(KeyVaultClient.java:216) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.KeyVaultClient.getAccessToken(KeyVaultClient.java:194) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.KeyVaultClient.getAliases(KeyVaultClient.java:233) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.refreshCertificates(KeyVaultCertificates.java:142) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.refreshCertificatesIfNeeded(KeyVaultCertificates.java:130) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.implementation.certificates.KeyVaultCertificates.getAliases(KeyVaultCertificates.java:100) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at com.azure.security.keyvault.jca.KeyVaultKeyStore.<init>(KeyVaultKeyStore.java:144) ~[azure-security-keyvault-jca-2.7.0.jar!/:2.7.0]"
"   at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]"
"   at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) ~[na:na]"
"   at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) ~[na:na]"
"   at java.base/java.lang.reflect.Constructor.newInstance(Unknown Source) ~[na:na]"
"   at java.base/java.security.Provider.newInstanceUtil(Unknown Source) ~[na:na]"
"   at java.base/java.security.Provider$Service.newInstance(Unknown Source) ~[na:na]"
"   at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source) ~[na:na]"
"   at java.base/sun.security.jca.GetInstance.getInstance(Unknown Source) ~[na:na]"
"   at java.base/java.security.Security.getImpl(Unknown Source) ~[na:na]"
"   at java.base/java.security.KeyStore.getInstance(Unknown Source) ~[na:na]"
"   at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:186) ~[tomcat-embed-core-9.0.68.jar!/:na]"
"   at 
backwind1233 commented 1 year ago

A workaround to this issue: Add an environment variable called WEBSITE_SITE_NAME with a non null value in the Azure Container Apps.

image
backwind1233 commented 1 year ago

azure-identity can work in Azure Contanier apps with Managed Identity, but our library can't, we should figure out the reason.

Botje commented 3 months ago

Container Apps Environments do not expose or proxy the IMDS endpoint to running Apps or Jobs. Instead, they offer a dedicated endpoint for retrieving tokens:

A container app with a managed identity exposes the identity endpoint by defining two environment variables:

  • IDENTITY_ENDPOINT - local URL from which your container app can request tokens.
  • IDENTITY_HEADER - a header used to help mitigate server-side request forgery (SSRF) attacks. The value is rotated by the platform.
To get a token for a resource, make an HTTP GET request to the endpoint, including the following parameters: Parameter name In Description
resource Query The Microsoft Entra resource URI of the resource for which a token should be obtained. The resource could be one of the Azure services that support Microsoft Entra authentication or any other resource URI.
api-version Query The version of the token API to be used. Use "2019-08-01" or later.
X-IDENTITY-HEADER Header The value of the IDENTITY_HEADER environment variable. This header mitigates server-side request forgery (SSRF) attacks.
client_id Query (Optional) The client ID of the user-assigned identity to be used. Can't be used on a request that includes principal_id, mi_res_id, or object_id. If all ID parameters (client_id, principal_id, object_id, and mi_res_id) are omitted, the system-assigned identity is used.
principal_id Query (Optional) The principal ID of the user-assigned identity to be used. object_id is an alias that may be used instead. Can't be used on a request that includes client_id, mi_res_id, or object_id. If all ID parameters (client_id, principal_id, object_id, and mi_res_id) are omitted, the system-assigned identity is used.
mi_res_id Query (Optional) The Azure resource ID of the user-assigned identity to be used. Can't be used on a request that includes principal_id, client_id, or object_id. If all ID parameters (client_id, principal_id, object_id, and mi_res_id) are omitted, the system-assigned identity is used.

Finally, the identity client consults this list of environment variables, whereas the keyvault libraries only consider the legacy app service case.