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

Adding design doc for to extend the capabilities of secretStores to a global scope #38

Merged
Merged
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
261 changes: 261 additions & 0 deletions recipe/2024-01-global-scope-secret-store.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
# Adding support to extend the capabilities of secretStores to a global scope.

* **Status**: Pending
* **Author**: Vishwanath Hiremath (@vishwahiremat)

## Overview

Today we have Application.Core/secretStores resource to securely manage secrets for the Application. However a gap exists if user wants to create a secret before application or environment is created. To address this limitation, we need to enhance the capabilities of the existing secretStores resource. The objective is to extend its support to a global scope, enabling users to store secrets prior to the creation of the application or environment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does the secretstore decide what Kubernetes namespace to use?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we're talking about the same thing. Let me try being more specific.

If I create an Applications.Core/secretStores resource today and I don't specify the kubernetes secret name + namespace, then it will use the namespace of the application (or environment).

For the global secret case, there's no application or environment, so there's no way to look up the namespace we're going to use.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From reading more of the doc, it looks like you did try to address this feedback as part of the proposal. Let's talk about it 👍



## Terms and definitions
| Term | Definition |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Global scope | The ability of the secretStores resource to operate universally, allowing users to manage secrets independently of a particular application or environment. |
| secretStores | Resource used to securely manage secrets for Environment and Application. |
| Private Terraform Repository | A private Terraform repository typically refers to a version control repository that contains Terraform module code, but is not publicly accessible. |

## Objectives

> **Issue Reference:** https://github.com/radius-project/radius/issues/7030

### Goals

- Enable support to extend the capabilities of secretStores to a global scope.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I am curious about is whether this type should move to UCP. Applications.Core defines it as a part of the Radius RP rather than part of UCP.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have usecases for this type in other parts of UCP then it would be better to rename/move than it would be to have two different secret types.

### Non goals
kachawla marked this conversation as resolved.
Show resolved Hide resolved
- To move secret store resource as part of UCP.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vishwahiremat Please log an issue to revisit this when you get a chance


### User scenarios (optional)

#### User story 1
As a operator I define and curate the set of terraform recipes that developers in my organization rely on. And these terraform modules are stored in a private module sources (e.g private git repository). I would need to securely store the credential information or use the existing secret (e.g kubernetes secret) with credential information. So it can be used while creating the env and registering recipes.

```diff
resource env 'Applications.Core/environments@2023-10-01-preview' = {
name: 'dsrp-resources-env-recipes-context-env'
location: 'global'
properties: {
compute: {
...
}
providers: {
...
}
recipeConfig: {
terraform: {
authentication:{
git:{
pat: {
"dev.azure.com": {
+ secret: secretStoreAzure.id
}
"github.com": {
+ secret: secretStoreGithub.id
}
}
}
}
}
}
recipes: {
'Applications.Datastores/mongoDatabases':{
default: {
templateKind: 'terraform'
templatePath: 'https://dev.azure.com/test-private-repo'
}
}
}
}
}
```


## Design
Today we use Application.Core/secretstores resource to store secrets/credentials information for an application but we cannot use it in this scenario as secretStores is application scoped and expects to have an application created before we create a secretStore.

And we cannot have secretStore created for environment scope in this scenario as we are adding the secret to the environment which creates cyclic dependency between environment and secretStore resource.

#### Application.Core/secretStores as a global scoped resource.
We could make secretStores as a global scoped resource by removing application as a required property.

```diff
"SecretStoreProperties": {
"type": "object",
"description": "The properties of SecretStore",
"properties": {
"environment": {
...
},
"application": {
...
},
"provisioningState": {
...
},
"status": {
...
},
"type": {
...
},
"data": {
"type": "object",
"description": "An object to represent key-value type secrets",
"additionalProperties": {
"$ref": "#/definitions/SecretValueProperties"
}
},
"resource": {
"type": "string",
"description": "The resource id of external secret store."
}
},
"required": [
- "application",
"data"
]
},
```
With this change we can create a secret store resource before an application or environment is created. But, if the user is creating a secretStore of kind kubernetes secret, it is deployed in application/environment namespace. But for secret resource with global scope use the `resource` property which is used to specify the secret ref of the existing secret to provide namespace and secret name details. User is expected to provide these details in `<namespace>/<secretName>` format for secretStore with global scope.

```diff
resource secretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'github'
properties:{
- app: app.id
+ resource: <namespace>/<secretName>
kachawla marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we might be able to use UCP style resource id instead of using <namespace>/<secretName>

e.g.

/planes/kubernetes/local/namespaces/<namespace>/providers/cores/Secrets/<secretName>"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the initial proposal of secretstore, we proposed using full resource id for Azure KeyVault in resource field when it refers to KeyVault Resource.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's talk about the semantics of this field.

vishwahiremat marked this conversation as resolved.
Show resolved Hide resolved
type: 'generic'
data: {
'pat': {
value: '<personal-access-token>'
}
'username': {
value: '<username>'
}
}
}
}
```

### API design

#### Typespec changes

radius/typespec/radius/v1/resources.tsp
```diff
+@doc("Base properties of a Global-scoped resource")
+model GlobalScopedResource {
+ @doc("Fully qualified resource ID for the environment that the application is linked to")
+ environment?: string;

+ @doc("Fully qualified resource ID for the application")
+ application?: string;

+ @doc("The status of the asynchronous operation.")
+ @visibility("read")
+ provisioningState?: ProvisioningState;

+ @doc("Status of a resource.")
+ @visibility("read")
+ status?: ResourceStatus;
+}
```

typespec/Applications.Core/secretstores.tsp

```diff
@doc("The properties of SecretStore")
model SecretStoreProperties {
- ...ApplicationScopedResource;
+ ...GlobalScopedResource;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is new type, pls describe it in detail


#suppress "@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property"
@doc("The type of secret store data")
type?: SecretStoreDataType = SecretStoreDataType.generic;

@doc("An object to represent key-value type secrets")
data: Record<SecretValueProperties>;

@doc("The resource id of external secret store.")
resource?: string;
}
```

## Alternatives considered

#### Adding default a namespace for global scoped secretstore resource.
Add a default namespace `global-secretStores` to store the global scoped secretStores.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or we could use radius-system.


```diff
resource secretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'github'
properties:{
- app: app.id
type: 'generic'
data: {
'pat': {
value: '<personal-access-token>'
}
'username': {
value: '<username>'
}
}
}
}
```


#### Adding a new property `namespace`

Add a new property `namespace` for kubernetes secret type.
```diff
resource secretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'github'
properties:{
- app: app.id
type: 'generic'
+ namespace: <namespace>
data: {
'pat': {
value: '<personal-access-token>'
}
'username': {
value: '<username>'
}
}
}
}
```
for existing kubernetes secret
```diff
resource secretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'github'
properties:{
- app: app.id
type: 'generic'
+ namespace: <namespace>
+ resource: <secretName>
data: {
'pat': {}
'username': {}
}
}
}
```

## Test plan

Unit tests:
- Update and add unit tests for changes in conversions for secret store.

Functional Tests:
- Functional test for private repository support takes care of this scenario.

## Development plan

Tasks:
- Adding typespec changes and conversions to secretstores resource.
- Adding unit tests for conversions.
- Updating secretStores frontend controller to support global scope.

Loading