This repository has been archived by the owner on Nov 22, 2023. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
expose API to createOrUpdate secrets
- Loading branch information
1 parent
1a39820
commit 3ccefa2
Showing
16 changed files
with
506 additions
and
52 deletions.
There are no files selected for viewing
85 changes: 85 additions & 0 deletions
85
api/src/main/java/keywhiz/api/automation/v2/CreateOrUpdateSecretRequestV2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package keywhiz.api.automation.v2; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.google.auto.value.AutoValue; | ||
import com.google.common.base.MoreObjects; | ||
import com.google.common.base.Strings; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.collect.ImmutableSet; | ||
import keywhiz.api.validation.ValidBase64; | ||
|
||
import javax.annotation.Nullable; | ||
import java.util.Base64; | ||
import java.util.Map; | ||
|
||
@AutoValue public abstract class CreateOrUpdateSecretRequestV2 { | ||
CreateOrUpdateSecretRequestV2() {} // prevent sub-classing | ||
|
||
public static Builder builder() { | ||
return new AutoValue_CreateOrUpdateSecretRequestV2.Builder() | ||
.description("") | ||
.metadata(ImmutableMap.of()) | ||
.expiry(0) | ||
.type(""); | ||
} | ||
|
||
@AutoValue.Builder public abstract static class Builder { | ||
// intended to be package-private | ||
abstract String content(); | ||
abstract CreateOrUpdateSecretRequestV2 autoBuild(); | ||
|
||
public abstract Builder content(String content); | ||
public abstract Builder description(String description); | ||
public abstract Builder metadata(ImmutableMap<String, String> metadata); | ||
public abstract Builder type(String type); | ||
public abstract Builder expiry(long expiry); | ||
|
||
/** | ||
* @throws IllegalArgumentException if builder data is invalid. | ||
*/ | ||
public CreateOrUpdateSecretRequestV2 build() { | ||
// throws IllegalArgumentException if content not valid base64. | ||
Base64.getDecoder().decode(content()); | ||
|
||
CreateOrUpdateSecretRequestV2 request = autoBuild(); | ||
return request; | ||
} | ||
} | ||
|
||
/** | ||
* Static factory method used by Jackson for deserialization | ||
*/ | ||
@SuppressWarnings("unused") | ||
@JsonCreator public static CreateOrUpdateSecretRequestV2 fromParts( | ||
@JsonProperty("content") String content, | ||
@JsonProperty("description") @Nullable String description, | ||
@JsonProperty("metadata") @Nullable Map<String, String> metadata, | ||
@JsonProperty("expiry") long expiry, | ||
@JsonProperty("type") @Nullable String type) { | ||
return builder() | ||
.content(content) | ||
.description(Strings.nullToEmpty(description)) | ||
.metadata(metadata == null ? ImmutableMap.of() : ImmutableMap.copyOf(metadata)) | ||
.expiry(expiry) | ||
.type(Strings.nullToEmpty(type)) | ||
.build(); | ||
} | ||
|
||
@JsonProperty("content") @ValidBase64 public abstract String content(); | ||
@JsonProperty("description") public abstract String description(); | ||
@JsonProperty("metadata") public abstract ImmutableMap<String, String> metadata(); | ||
@JsonProperty("expiry") public abstract long expiry(); | ||
@JsonProperty("type") public abstract String type(); | ||
|
||
@Override public final String toString() { | ||
return MoreObjects.toStringHelper(this) | ||
.add("content", "[REDACTED]") | ||
.add("description", description()) | ||
.add("metadata", metadata()) | ||
.add("expiry", expiry()) | ||
.add("type", type()) | ||
.omitNullValues() | ||
.toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
cli/src/main/java/keywhiz/cli/commands/CreateOrUpdateAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package keywhiz.cli.commands; | ||
|
||
import com.fasterxml.jackson.core.type.TypeReference; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.google.common.base.Throwables; | ||
import com.google.common.collect.ImmutableMap; | ||
import com.google.common.io.ByteStreams; | ||
import keywhiz.cli.configs.CreateOrUpdateActionConfig; | ||
import keywhiz.client.KeywhizClient; | ||
import org.joda.time.DateTime; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
import static java.lang.String.format; | ||
import static keywhiz.cli.Utilities.VALID_NAME_PATTERN; | ||
import static keywhiz.cli.Utilities.validName; | ||
|
||
public class CreateOrUpdateAction implements Runnable { | ||
private static final Logger logger = LoggerFactory.getLogger(CreateOrUpdateAction.class); | ||
|
||
private final CreateOrUpdateActionConfig createOrUpdateActionConfig; | ||
private final KeywhizClient keywhizClient; | ||
private final ObjectMapper mapper; | ||
|
||
InputStream stream = System.in; | ||
|
||
public CreateOrUpdateAction(CreateOrUpdateActionConfig createOrUpdateActionConfig, KeywhizClient client, ObjectMapper mapper) { | ||
this.createOrUpdateActionConfig = createOrUpdateActionConfig; | ||
this.keywhizClient = client; | ||
this.mapper = mapper; | ||
} | ||
|
||
@Override public void run() { | ||
String secretName = createOrUpdateActionConfig.secretName; | ||
|
||
if (secretName == null || !validName(secretName)) { | ||
throw new IllegalArgumentException(format("Invalid name, must match %s", VALID_NAME_PATTERN)); | ||
} | ||
|
||
byte[] content = readSecretContent(); | ||
createOrUpdateSecret(secretName, content, getMetadata(), getExpiry()); | ||
} | ||
|
||
private void createOrUpdateSecret(String secretName, byte[] content, | ||
ImmutableMap<String, String> metadata, long expiry) { | ||
try { | ||
keywhizClient.createOrUpdateSecret(secretName, "", content, metadata, expiry); | ||
logger.info("createOrUpdate secret '{}'.", secretName); | ||
} catch (IOException e) { | ||
throw Throwables.propagate(e); | ||
} | ||
} | ||
|
||
private ImmutableMap<String, String> getMetadata() { | ||
ImmutableMap<String, String> metadata = ImmutableMap.of(); | ||
String jsonBlob = createOrUpdateActionConfig.json; | ||
if (jsonBlob != null && !jsonBlob.isEmpty()) { | ||
TypeReference typeRef = new TypeReference<ImmutableMap<String, String>>() {}; | ||
try { | ||
metadata = mapper.readValue(jsonBlob, typeRef); | ||
} catch (IOException e) { | ||
throw Throwables.propagate(e); | ||
} | ||
validateMetadata(metadata); | ||
} | ||
return metadata; | ||
} | ||
|
||
private long getExpiry() { | ||
String expiry = createOrUpdateActionConfig.expiry; | ||
if (expiry != null) { | ||
try { | ||
return Long.parseLong(expiry); | ||
} catch (NumberFormatException e) { | ||
} | ||
DateTime dt = new DateTime(expiry); | ||
return dt.getMillis(); | ||
} | ||
return 0; | ||
} | ||
|
||
private byte[] readSecretContent() { | ||
try { | ||
byte[] content = ByteStreams.toByteArray(stream); | ||
if (content.length == 0) { | ||
throw new RuntimeException("Secret content empty!"); | ||
} | ||
return content; | ||
} catch (IOException e) { | ||
throw Throwables.propagate(e); | ||
} | ||
} | ||
|
||
private static void validateMetadata(ImmutableMap<String, String> metadata) { | ||
for (ImmutableMap.Entry<String, String> entry : metadata.entrySet()) { | ||
String key = entry.getKey(); | ||
String value = entry.getValue(); | ||
|
||
// We want to perform strong validation of the metadata to make sure it is well formed. | ||
if (!key.matches("(owner|group|mode)")) { | ||
throw new IllegalArgumentException(format("Illegal metadata key %s", key)); | ||
} | ||
|
||
if (key.equals("mode") && !value.matches("0[0-7]+")) { | ||
throw new IllegalArgumentException(format("mode %s is not proper octal", value)); | ||
} | ||
} | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
cli/src/main/java/keywhiz/cli/configs/CreateOrUpdateActionConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright (C) 2015 Square, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package keywhiz.cli.configs; | ||
|
||
import com.beust.jcommander.Parameter; | ||
import com.beust.jcommander.Parameters; | ||
|
||
import java.util.List; | ||
|
||
@Parameters(commandDescription = "Create or update secret.") | ||
public class CreateOrUpdateActionConfig { | ||
@Parameter(names = "--secret", description = "Name of the secret to add", required = true) | ||
public String secretName; | ||
|
||
@Parameter(names = "--json", description = "Metadata JSON blob") | ||
public String json; | ||
|
||
@Parameter(names = { "-e", "--expiry" }, description = "Secret expiry. For keystores, it is recommended to use the expiry of the earliest key. Format should be 2006-01-02T15:04:05Z or seconds since epoch.") | ||
public String expiry; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.