Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add toolkit lib for Azure Key Vault #2394

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,29 @@ azure/monitor.delete_log_analytics_workspace.workspace=delete Log Analytics Work
azure/account.load_subscriptions=load subscriptions
azure/account.load_subscriptions.tenant=load subscriptions of tenant ({0})
azure/account.reload_subscriptions=reload subscriptions
azure/keyvault.load_key_vault.key_vault=load Key Vault ({0})
azure/keyvault.delete_key_vault.key_vault=delete Key Vault ({0})
azure/keyvault.create_keyvault.keyvault=create Key Vault ({0})
azure/keyvault.update_keyvault.keyvault=update Key Vault ({0})
azure/keyvault.load_secret.secret=load Secret ({0})
azure/keyvault.delete_secret.secret=delete Secret ({0})
azure/keyvault.create_secret.secret=create Secret ({0})
azure/keyvault.update_secret.secret=update Secret ({0})
azure/keyvault.load_secret_version.version=load Secret Version ({0})
azure/keyvault.create_secret_version.version=create Secret Version ({0})
azure/keyvault.update_secret_version.version=update Secret Version ({0})
azure/keyvault.load_key.key=load Key ({0})
azure/keyvault.delete_key.key=delete Key ({0})
azure/keyvault.create_key.key=create Key ({0})
azure/keyvault.update_key.key=update Key ({0})
azure/keyvault.load_key_version.version=load Key Version ({0})
azure/keyvault.create_key_version.version=create Key Version ({0})
azure/keyvault.update_key_version.version=update Key Version ({0})
azure/keyvault.load_certificate.certificate=load Certificate ({0})
azure/keyvault.delete_certificate.certificate=delete Certificate ({0})
azure/keyvault.create_certificate.certificate=create Certificate ({0})
azure/keyvault.update_certificate.certificate=update Certificate ({0})
azure/keyvault.load_certificate_version.version=load Certificate Version ({0})
azure/keyvault.create_certificate_version.version=create Certificate Version ({0})
azure/keyvault.update_certificate_version.version=update Certificate Version ({0})

Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class AzureConfiguration {
private String databasePasswordSaveType;
private Boolean telemetryEnabled; // null means true
private String functionCoreToolsPath;
private String azureCliPath;
private String dotnetRuntimePath;
private String storageExplorerPath;
private String proxySource;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;

@Slf4j
@ToString(onlyExplicitlyIncluded = true)
Expand Down Expand Up @@ -123,7 +124,7 @@ protected final R loadRemoteFromAzure() {
return this.getModule().loadResourceFromAzure(this.getName(), this.getResourceGroupName());
} catch (final Exception e) {
log.debug("[{}:{}]:loadRemote()=EXCEPTION", this.module.getName(), this.getName(), e);
if (isNotFoundException(e)) {
if (is404(e)) {
return null;
}
throw e;
Expand Down Expand Up @@ -232,7 +233,7 @@ private void deleteFromAzure() {
try {
this.getModule().deleteResourceFromAzure(this.getId());
} catch (final Exception e) {
if (isNotFoundException(e)) {
if (is404(e)) {
log.debug("[{}]:delete()->deleteResourceFromAzure()=SC_NOT_FOUND", this.name, e);
} else {
this.getCachedSubModules().stream().flatMap(m -> m.listCachedResources().stream()).forEach(r -> r.setStatus(Status.UNKNOWN));
Expand Down Expand Up @@ -333,13 +334,27 @@ protected boolean isAuthRequired() {
return true;
}

public static boolean isNotFoundException(Throwable t) {
public static boolean is404(Throwable t) {
return isHttpException(t, HttpStatus.SC_NOT_FOUND);
}

public static boolean is400(Throwable t) {
return isHttpException(t, HttpStatus.SC_BAD_REQUEST);
}

/**
* @param httpStatusCode {@link HttpStatus}
*/
public static boolean isHttpException(Throwable t, int httpStatusCode) {
return isHttpException(t, r -> r.getStatusCode() == httpStatusCode);
}

public static boolean isHttpException(Throwable t, Predicate<HttpResponse> predicate) {
final Throwable cause = t instanceof HttpResponseException ? t : ExceptionUtils.getRootCause(t);
return Optional.ofNullable(cause).filter(c -> cause instanceof HttpResponseException)
.map(c -> ((HttpResponseException) c))
.map(HttpResponseException::getResponse)
.map(HttpResponse::getStatusCode)
.filter(c -> c == HttpStatus.SC_NOT_FOUND)
.filter(predicate)
.isPresent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource.isNotFoundException;
import static com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource.is400;
import static com.microsoft.azure.toolkit.lib.common.model.AbstractAzResource.is404;
import static com.microsoft.azure.toolkit.lib.common.model.AzResource.RESOURCE_GROUP_PLACEHOLDER;
import static com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemeter.OPERATION_NAME;
import static com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemeter.OP_NAME;
Expand Down Expand Up @@ -157,7 +158,7 @@ private void reloadResources() {
this.setResources(loadedResources);
} catch (final Exception e) {
log.debug("[{}]:reloadResources->setResources([])", this.name);
if (isNotFoundException(e)) {
if (is404(e)) {
log.debug("[{}]:reloadResources->loadResourceFromAzure()=SC_NOT_FOUND", this.name, e);
this.setResources(Collections.emptyMap());
} else {
Expand Down Expand Up @@ -287,11 +288,9 @@ public T get(@Nonnull String name, @Nullable String rgName) {
} catch (final Exception e) {
log.debug("[{}]:get({}, {})->loadResourceFromAzure()=EXCEPTION", this.name, name, resourceGroup, e);
final Throwable cause = e instanceof HttpResponseException ? e : ExceptionUtils.getRootCause(e);
if (cause instanceof HttpResponseException) {
if (!isNotFoundException(e)) {
log.debug("[{}]:get({}, {})->loadResourceFromAzure()=SC_NOT_FOUND", this.name, name, resourceGroup, e);
throw e;
}
if (cause instanceof HttpResponseException && !is404(e) && !is400(e)) {
log.debug("[{}]:get({}, {})->loadResourceFromAzure()=SC_NOT_FOUND", this.name, name, resourceGroup, e);
throw e;
}
}
if (Objects.isNull(remote)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ protected CosmosDBAccount newResource(@Nonnull String name, @Nullable String res
try {
return c.getByResourceGroup(resourceGroupName, name);
} catch (Throwable e) {
if (AbstractAzResource.isNotFoundException(e)) {
if (AbstractAzResource.is404(e)) {
return null;
}
throw e;
Expand Down
117 changes: 117 additions & 0 deletions azure-toolkit-libs/azure-toolkit-keyvault-lib/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-libs</artifactId>
<version>0.39.0-SNAPSHOT</version>
</parent>

<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-keyvault-lib</artifactId>
<version>0.39.0-SNAPSHOT</version>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<show>private</show>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<!-- https://mvnrepository.com/artifact/org.codehaus.mojo/aspectj-maven-plugin -->
<!-- http://www.quabr.com/62976155/aspectj-maven-plugin-1-11-missing-tools-jar-issue-with-jdk-11 -->
<groupId>com.nickwongdev</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<showWeaveInfo>false</showWeaveInfo>
<source>1.8</source>
<target>1.8</target>
<Xlint>ignore</Xlint>
<complianceLevel>1.8</complianceLevel>
<encoding>UTF-8</encoding>
<verbose>false</verbose>
<outxml>true</outxml>
<forceAjcCompile>true</forceAjcCompile>
<sources/><!-- this is important!-->
<aspectLibraries>
<aspectLibrary>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-common-lib</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<id>compile-with-aspectj</id>
<phase>process-classes</phase>
<configuration>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
</configuration>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile-with-aspectj</id>
<phase>process-test-classes</phase>
<configuration>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/test-classes</weaveDirectory>
</weaveDirectories>
</configuration>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.azure.resourcemanager</groupId>
<artifactId>azure-resourcemanager-keyvault</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-certificates</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-toolkit-auth-lib</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

package com.microsoft.azure.toolkit.lib.keyvault;

import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.UserAgentPolicy;
import com.azure.core.management.profile.AzureProfile;
import com.azure.resourcemanager.keyvault.KeyVaultManager;
import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.fluentcore.policy.ProviderRegistrationPolicy;
import com.azure.resourcemanager.resources.models.Providers;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureConfiguration;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzService;
import com.microsoft.azure.toolkit.lib.common.model.AbstractAzServiceSubscription;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Optional;

public class AzureKeyVault extends AbstractAzService<KeyVaultSubscription, KeyVaultManager> {
public AzureKeyVault() {
super("Microsoft.KeyVault");
}

@Nonnull
public KeyVaultModule keyVaults(@Nonnull String subscriptionId) {
final KeyVaultSubscription rm = get(subscriptionId, null);
assert rm != null;
return rm.getKeyVaultModule();
}

@Nonnull
@Override
protected KeyVaultSubscription newResource(@Nonnull KeyVaultManager keyVaultManager) {
return new KeyVaultSubscription(keyVaultManager.serviceClient().getSubscriptionId(), this);
}

@Nullable
@Override
protected KeyVaultManager loadResourceFromAzure(@Nonnull String subscriptionId, String resourceGroup) {
final Account account = Azure.az(AzureAccount.class).account();
final String tenantId = account.getSubscription(subscriptionId).getTenantId();
final AzureConfiguration config = Azure.az().config();
final String userAgent = config.getUserAgent();
final HttpLogOptions logOptions = new HttpLogOptions();
logOptions.setLogLevel(Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE));
final AzureProfile azureProfile = new AzureProfile(tenantId, subscriptionId, account.getEnvironment());
final Providers providers = ResourceManager.configure()
.withHttpClient(AbstractAzServiceSubscription.getDefaultHttpClient())
.withPolicy(new UserAgentPolicy(userAgent))
.authenticate(account.getTokenCredential(subscriptionId), azureProfile)
.withSubscription(subscriptionId).providers();
return KeyVaultManager
.configure()
.withHttpClient(AbstractAzServiceSubscription.getDefaultHttpClient())
.withLogOptions(logOptions)
.withPolicy(new UserAgentPolicy(userAgent))
.withPolicy(new ProviderRegistrationPolicy(providers)) // add policy to auto register resource providers
.authenticate(account.getTokenCredential(subscriptionId), azureProfile);
}

@Nonnull
@Override
public String getResourceTypeName() {
return "Key Vaults";
}

@Nonnull
public String getServiceNameForTelemetry() {
return "keyvault";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

package com.microsoft.azure.toolkit.lib.keyvault;

import com.microsoft.azure.toolkit.lib.common.model.AzResource;

import java.util.List;
import java.util.Optional;

public interface Credential extends AzResource {
KeyVault getKeyVault();

CredentialVersion getCurrentVersion();

List<? extends CredentialVersion> listVersions();
default void enable() {
Optional.ofNullable(getCurrentVersion()).ifPresent(CredentialVersion::enable);
}

default void disable() {
Optional.ofNullable(getCurrentVersion()).ifPresent(CredentialVersion::enable);
}

default Boolean isEnabled() {
return Optional.ofNullable(getCurrentVersion()).map(CredentialVersion::isEnabled).orElse(false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/

package com.microsoft.azure.toolkit.lib.keyvault;

import com.microsoft.azure.toolkit.lib.common.model.AzResource;

import javax.annotation.Nonnull;

public interface CredentialVersion extends AzResource {
@Nonnull
Credential getCredential();

default KeyVault getKeyVault() {
return getCredential().getKeyVault();
}

void enable();

void disable();

Boolean isEnabled();

String getShowCredentialCommand();

String getDownloadCredentialCommand(final String path);
}
Loading
Loading