Skip to content

Commit f612b46

Browse files
authored
CC-6583: Add support for SSH TrustedUserCAKeys (#11702)
1 parent 5e73663 commit f612b46

File tree

12 files changed

+75
-22
lines changed

12 files changed

+75
-22
lines changed

.changeset/brave-plants-dream.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
"@cloudflare/containers-shared": minor
3+
"@cloudflare/workers-utils": minor
4+
"wrangler": minor
5+
---
6+
7+
Add support for trusted_user_ca_keys in Wrangler
8+
9+
You can now configure SSH trusted user CA keys for containers. Add the following to your wrangler.toml:
10+
11+
```toml
12+
[[containers.trusted_user_ca_keys]]
13+
public_key = "ssh-ed25519 AAAAC3..."
14+
```
15+
16+
This allows you to specify CA public keys that can be used to verify SSH user certificates.

packages/containers-shared/src/client/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export { SecretNotFound } from "./models/SecretNotFound";
193193
export type { SSHPublicKey } from "./models/SSHPublicKey";
194194
export type { SSHPublicKeyID } from "./models/SSHPublicKeyID";
195195
export type { SSHPublicKeyItem } from "./models/SSHPublicKeyItem";
196-
export type { SSHPublicKeyItemV3 } from "./models/SSHPublicKeyItemV3";
196+
export type { UserSSHPublicKey } from "./models/UserSSHPublicKey";
197197
export { SSHPublicKeyNotFoundError } from "./models/SSHPublicKeyNotFoundError";
198198
export type { UnAuthorizedError } from "./models/UnAuthorizedError";
199199
export type { UnixTimestamp } from "./models/UnixTimestamp";

packages/containers-shared/src/client/models/DeploymentV2.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import type { Observability } from "./Observability";
2727
import type { Placement } from "./Placement";
2828
import type { Ref } from "./Ref";
2929
import type { SSHPublicKeyID } from "./SSHPublicKeyID";
30-
import type { SSHPublicKeyItemV3 } from "./SSHPublicKeyItemV3";
30+
import type { UserSSHPublicKey } from "./UserSSHPublicKey";
3131
import type { WranglerSSHConfig } from "./WranglerSSHConfig";
3232

3333
/**
@@ -44,7 +44,7 @@ export type DeploymentV2 = {
4444
image: Image;
4545
location: DeploymentLocation;
4646
wrangler_ssh?: WranglerSSHConfig;
47-
authorized_keys?: Array<SSHPublicKeyItemV3>;
47+
authorized_keys?: Array<UserSSHPublicKey>;
4848
/**
4949
* A list of SSH public key IDs from the account
5050
*/

packages/containers-shared/src/client/models/ModifyUserDeploymentConfiguration.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { Observability } from "./Observability";
1818
import type { Port } from "./Port";
1919
import type { ProvisionerConfiguration } from "./ProvisionerConfiguration";
2020
import type { SSHPublicKeyID } from "./SSHPublicKeyID";
21-
import type { SSHPublicKeyItemV3 } from "./SSHPublicKeyItemV3";
21+
import type { UserSSHPublicKey } from "./UserSSHPublicKey";
2222
import type { WranglerSSHConfig } from "./WranglerSSHConfig";
2323

2424
/**
@@ -27,7 +27,8 @@ import type { WranglerSSHConfig } from "./WranglerSSHConfig";
2727
export type ModifyUserDeploymentConfiguration = {
2828
image?: Image;
2929
wrangler_ssh?: WranglerSSHConfig;
30-
authorized_keys?: Array<SSHPublicKeyItemV3>;
30+
authorized_keys?: Array<UserSSHPublicKey>;
31+
trusted_user_ca_keys?: Array<UserSSHPublicKey>;
3132
/**
3233
* A list of SSH public key IDs from the account
3334
*/

packages/containers-shared/src/client/models/UserDeploymentConfiguration.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import type { Observability } from "./Observability";
1818
import type { Port } from "./Port";
1919
import type { ProvisionerConfiguration } from "./ProvisionerConfiguration";
2020
import type { SSHPublicKeyID } from "./SSHPublicKeyID";
21-
import type { SSHPublicKeyItemV3 } from "./SSHPublicKeyItemV3";
21+
import type { UserSSHPublicKey } from "./UserSSHPublicKey";
2222
import type { WranglerSSHConfig } from "./WranglerSSHConfig";
2323

2424
/**
@@ -27,7 +27,8 @@ import type { WranglerSSHConfig } from "./WranglerSSHConfig";
2727
export type UserDeploymentConfiguration = {
2828
image: Image;
2929
wrangler_ssh?: WranglerSSHConfig;
30-
authorized_keys?: Array<SSHPublicKeyItemV3>;
30+
authorized_keys?: Array<UserSSHPublicKey>;
31+
trusted_user_ca_keys?: Array<UserSSHPublicKey>;
3132
/**
3233
* A list of SSH public key IDs from the account
3334
*/

packages/containers-shared/src/client/models/SSHPublicKeyItemV3.ts renamed to packages/containers-shared/src/client/models/UserSSHPublicKey.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
import type { SSHPublicKey } from "./SSHPublicKey";
66

77
/**
8-
* An SSH public key attached to a specific application or account.
8+
* SSH public key provided by the user
99
*/
10-
export type SSHPublicKeyItemV3 = {
11-
name: string;
10+
export type UserSSHPublicKey = {
11+
name?: string;
1212
public_key: SSHPublicKey;
1313
};

packages/containers-shared/src/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {
22
ApplicationAffinityColocation,
33
InstanceType,
44
SchedulingPolicy,
5-
SSHPublicKeyItemV3,
5+
UserSSHPublicKey,
66
WranglerSSHConfig,
77
} from "./client";
88
import type { ApplicationAffinityHardwareGeneration } from "./client/models/ApplicationAffinityHardwareGeneration";
@@ -79,7 +79,8 @@ export type SharedContainerConfig = {
7979
rollout_kind: "full_auto" | "full_manual" | "none";
8080
rollout_active_grace_period: number;
8181
wrangler_ssh?: WranglerSSHConfig;
82-
authorized_keys?: Array<SSHPublicKeyItemV3>;
82+
authorized_keys?: Array<UserSSHPublicKey>;
83+
trusted_user_ca_keys?: Array<UserSSHPublicKey>;
8384
constraints: {
8485
regions?: string[];
8586
cities?: string[];

packages/workers-utils/src/config/environment.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ export type ContainerApp = {
190190
*/
191191
authorized_keys?: { name: string; public_key: string }[];
192192

193+
/**
194+
* Trusted user CA keys to put in the container's trusted_user_ca_keys file.
195+
*/
196+
trusted_user_ca_keys?: { name?: string; public_key: string }[];
197+
193198
/**
194199
* @deprecated Use top level `containers` fields instead.
195200
* `configuration.image` should be `image`

packages/workers-utils/src/config/validation.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3059,6 +3059,7 @@ function validateContainerApp(
30593059
"instance_type",
30603060
"wrangler_ssh",
30613061
"authorized_keys",
3062+
"trusted_user_ca_keys",
30623063
"configuration",
30633064
"constraints",
30643065
"affinities",
@@ -3104,15 +3105,6 @@ function validateContainerApp(
31043105
`${field}.wrangler_ssh.port must be a number between 1 and 65535 inclusive`
31053106
);
31063107
}
3107-
3108-
if (
3109-
!("authorized_keys" in containerAppOptional) &&
3110-
containerAppOptional.wrangler_ssh.enabled
3111-
) {
3112-
diagnostics.errors.push(
3113-
`${field}.authorized_keys must be provided if wrangler ssh is enabled`
3114-
);
3115-
}
31163108
}
31173109

31183110
if ("authorized_keys" in containerAppOptional) {
@@ -3142,6 +3134,35 @@ function validateContainerApp(
31423134
}
31433135
}
31443136

3137+
if ("trusted_user_ca_keys" in containerAppOptional) {
3138+
if (!Array.isArray(containerAppOptional.trusted_user_ca_keys)) {
3139+
diagnostics.errors.push(
3140+
`${field}.trusted_user_ca_keys must be an array`
3141+
);
3142+
} else {
3143+
for (const index in containerAppOptional.trusted_user_ca_keys) {
3144+
const fieldPath = `${field}.trusted_user_ca_keys[${index}]`;
3145+
const key = containerAppOptional.trusted_user_ca_keys[index];
3146+
3147+
if (!isOptionalProperty(key, "name", "string")) {
3148+
diagnostics.errors.push(`${fieldPath}.name must be a string`);
3149+
}
3150+
3151+
if (!isRequiredProperty(key, "public_key", "string")) {
3152+
diagnostics.errors.push(
3153+
`${fieldPath}.public_key must be a string`
3154+
);
3155+
}
3156+
3157+
if (!key.public_key.toLowerCase().startsWith("ssh-ed25519")) {
3158+
diagnostics.errors.push(
3159+
`${fieldPath}.public_key is a unsupported key type. Please provide a ED25519 public key.`
3160+
);
3161+
}
3162+
}
3163+
}
3164+
}
3165+
31453166
// Instance Type validation: When present, the instance type should be either (1) a string
31463167
// representing a predefined instance type or (2) an object that optionally defines vcpu,
31473168
// memory, and disk.

packages/wrangler/src/__tests__/containers/config.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,12 @@ describe("getNormalizedContainerOptions", () => {
788788
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC0chNcjRotdsxXTwPPNoqVCGn4EcEWdUkkBPNm/v4gm",
789789
},
790790
],
791+
trusted_user_ca_keys: [
792+
{
793+
public_key:
794+
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC0chNcjRotdsxXTwPPNoqVCGn4EcEWdUkkBPNm/v4gm",
795+
},
796+
],
791797
},
792798
],
793799
durable_objects: {

0 commit comments

Comments
 (0)