-
Notifications
You must be signed in to change notification settings - Fork 50
validate & recreate SA keys if necessary #160
Conversation
@honnix PTAL |
@@ -43,6 +44,20 @@ public ServiceAccountKey createP12Key(String serviceAccount) throws IOException | |||
.setPrivateKeyType("TYPE_PKCS12_FILE")); | |||
} | |||
|
|||
public boolean keyExists(String serviceAccount, String keyName) throws IOException { | |||
try { | |||
ServiceAccountKey key = iam.projects().serviceAccounts().keys() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need of this variable.
final ServiceAccountKey jsonKey; | ||
final ServiceAccountKey p12Key; | ||
try { | ||
jsonKey = Json.OBJECT_MAPPER.readValue(jsonKeyJson, ServiceAccountKey.class); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only private key gets stored in kube secret, not the complete JSON. https://github.com/spotify/styx/pull/160/files#diff-d96c43ca98b2c4d50df1a802530ab077R266
Get key name from annotation instead?
keysExist = serviceAccountKeyManager.keyExists(serviceAccount, jsonKey.getName()) | ||
&& serviceAccountKeyManager.keyExists(serviceAccount, p12Key.getName()); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's stick to InvalidExecutionException
.
@@ -25,9 +25,11 @@ | |||
import static com.spotify.styx.docker.KubernetesPodEventTranslatorTest.running; | |||
import static com.spotify.styx.docker.KubernetesPodEventTranslatorTest.terminated; | |||
import static com.spotify.styx.docker.KubernetesPodEventTranslatorTest.waiting; | |||
import static java.nio.charset.StandardCharsets.UTF_8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused import
if (runSpec.secret().isPresent()) { | ||
final WorkflowConfiguration.Secret specSecret = runSpec.secret().get(); | ||
private void ensureCustomSecret(WorkflowInstance workflowInstance, RunSpec runSpec) { | ||
runSpec.secret().ifPresent(specSecret -> { | ||
final Secret secret = client.secrets().withName(specSecret.name()).get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel like to incorporate this check https://github.com/spotify/styx/pull/153/files#diff-d96c43ca98b2c4d50df1a802530ab077R160 ? Or I can open another PR after this one has been merged. Having #153 opened doesn't make much sense due to the massive change brought by this PR.
}); | ||
} | ||
|
||
private void ensureServiceAccountKeySecret(WorkflowInstance workflowInstance, RunSpec runSpec) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So as we discussed, this method is supposed to be synchronized
as the first simplest approach.
21c1e27
to
a585405
Compare
a585405
to
9c57da2
Compare
9c57da2
to
b597cd5
Compare
@honnix PTAL again |
@bergman PTAL as well |
if (e.getStatusCode() == 404) { | ||
return false; | ||
} | ||
throw e; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In most of the code we use throw Throwables.propagate(e)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a discussion that Throwables.propagate
has been deprecated by Google. Also in this case we don't need a RuntimeException
I think.
if (!serviceAccountExists) { | ||
LOG.error("[AUDIT] Workflow {} refers to non-existent service account {}", workflowInstance.workflowId(), | ||
serviceAccount); | ||
throw new InvalidExecutionException("Referenced service account '" + serviceAccount + "' was not found"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent quoting (here '
s surround service account and not elsewhere) :] I do see that this was unchanged in this PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. I don't think there is a need to quote. It's a full string without any space anyway.
return; | ||
} | ||
|
||
LOG.warn("[AUDIT] Service account keys have been deleted for {}, recreating", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lie the first time round, they just haven't been created, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it seems noisy to warn
about it - isn't info
more appropriate, as key rotation is legitimate business?
(Suggested convention: error
for internal errors, "this line should never happen" type of things; warn
for external errors that will stop workflows from running if they persist; info
or lower for everything else.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the keys are not created the secret shouldn't be in kube. We check secret first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. That I agree.
final Map<String, String> annotations = ImmutableMap.of( | ||
STYX_WORKFLOW_SA_JSON_KEY_NAME_ANNOTATION, jsonKey.getName(), | ||
STYX_WORKFLOW_SA_P12_KEY_NAME_ANNOTATION, p12Key.getName(), | ||
STYX_WORKFLOW_SA_SECRET_ANNOTATION, serviceAccount |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it confusing to call it "secret annotation" if it stores serviceAccount? I expect "SA_ID_ANNOTATION" or "SA_ANNOTATION".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Confusing indeed. Will fix.
|
||
client.secrets().create(newSecret); | ||
|
||
LOG.info("[AUDIT] Secret {} created for {} referred to by workflow {}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"For" might read ambiguously, as in "for [use by this service account]", while it's actually "storing [this service account's private key!!!11]".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about "Secret [secret1] created to store keys of [sa] referred by ..."?
|
||
stateManager.receive(Event.terminate(WORKFLOW_INSTANCE, Optional.of(0))); | ||
stateManager.receive(Event.success(WORKFLOW_INSTANCE)); | ||
kdr.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why here too? It seems it's done in tearDown
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general cases we create in setup and for a few cases the default is not good enough so we close it and create a new one. Not very good indeed. Shall we address this in separated PR?
LGTM apart from those naming and wording nitpickings. |
Also makes SA key secret checking and creation single threaded to avoid concurrent executions of workflows using the same service account from stepping on each others feet.