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 Security Group support #65

Merged

Conversation

nsricardor
Copy link
Contributor

@nsricardor nsricardor commented Oct 21, 2024

This PR introduces the SecurityGroup CRD, the provider-specific data structure, security-group controller and the api

@nsricardor nsricardor marked this pull request as ready for review October 21, 2024 10:59
// SecurityGroupID is the security group ID.
SecurityGroupID *string `json:"securityGroupID,omitempty"`
// Rules are the security group rules.
Rules []rules.SecGroupRule `json:"rules,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should be importing/exposing gophercloud types, there's jsut way too much unnecessary crap in there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😮 I updated it but forgot to push. The gophercloud type is missing the JSON tag on a few elements, which is causing the CRD generation to fail. I'll fix that - thanks for the review so far! ;)

Copy link
Member

Choose a reason for hiding this comment

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

I'm trying to keep on top of it! It's a pain if you're having to use replace in go.mod too often... here's something I find useful:

#!/bin/bash

export GOPRIVATE=github.com/unikorn-cloud

go mod edit -replace $1=$1@$2
go mod tidy

@nsricardor nsricardor changed the title Add Security Group CRD Add Security Group support Oct 24, 2024
Copy link
Member

@spjmurray spjmurray left a comment

Choose a reason for hiding this comment

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

On the whole, I'm seriously impressed you have got this far! See the comments below, I think that perhaps the data structures and APIs aren't quite correct and that leads to algorithmic complexity which makes my COVID infested head hurt! Let me know your thoughts...

// Port is the port or range of ports.
Port SecurityGroupRulePort `json:"port"`
// Cidr is the CIDR block to allow traffic from.
Cidr *unikornv1core.IPv4Prefix `json:"cidr"`
Copy link
Member

Choose a reason for hiding this comment

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

Variable should be capitalized, surprised the linter didn't complain!

if rule.Port.Range != nil {
return rule.Port.Range.Start, rule.Port.Range.End
}
return 0, 0 // Return 0,0 if no port information is available
Copy link
Member

Choose a reason for hiding this comment

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

There's a couple things we should do here

  • Return an error, not magic numbers
  • In the CRD, you can use CEL to indicate that at least one is required...
// +kubebuilder:validation:XValidation:message="at least one of number or range must be defined",rule=(has(self.number) || has(self.range))
type Thing struct {
  Number *int
  Range  *Range
}

For more information see:

And feel EMPOWERED!!

Range *SecurityGroupRulePortRange `json:"range,omitempty"`
}

type SecurityGroupRule struct {
Copy link
Member

Choose a reason for hiding this comment

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

I think the best thing we can do here for general cleanliness and ease of use is to have each rule have a unique identifier and also a description e.g.

kind: SecurityGroup
spec:
  ingress:
  - id: 9575b2ef-2eee-4c75-a6e8-59537984185a
    description: OpenSSH
    port:
      number: 22

The description is just to make the UX a lot better, sure Adam will thank you in future!

The ID however can be used in the mapping from unikorn to openstack e.g.

kind: OpenstackSecurityGroup
spec:
  id: 13a4f72a-9467-4262-be73-021d44541cc8
  rules:
  - id: 9575b2ef-2eee-4c75-a6e8-59537984185a
    openstackID: f7fc698a-628a-4652-8355-9d3b69c9b120

I think this will improve the reconcile logic a whole heap as you're just concerned with IDs and not the whole tuple of direction, port range, protocol etc etc. Obviously the API will need to be tweaked to be:

GET/POST /.../securitygroups
GET?PUT/DELETE /.../securitygroups/{id}
GET/POST /.../securitygroups/{id}/rules
GET/PUT/DELETE /.../securitygroups/{id}/rules/{id}

A call to create a rule will generate a unique UUID like creation of the security group itself. I am aware of time, so rather than have rules as a separate CRD and controller we leave that bit the way it is.

As I always say, if the data structure is not quite right, the code will suck!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestions! Implementing a unique identifier for each rule did help simplify the reconciliation logic somewhat, but splitting the CRDs made a bigger difference. I ended up splitting the CRDs and moving the security group reconciliation to its own controller, which eliminated the need to iterate over the list of rules entirely.

@spjmurray
Copy link
Member

+5,975 −631 lol 🤣

@spjmurray
Copy link
Member

Actually, there are still a shit load of files to review if I "viewed" the generated/boilerplate ones... I'll just test the behaviour and see what happens. That'll be quickly reduce the cognitive load further...

@spjmurray
Copy link
Member

spjmurray commented Oct 30, 2024

First test...

[Wed 30 Oct 13:49:02 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups -X POST -H 'Content-Type: application/json' -d '{"metadata":{"name":"foo"}}'
{"metadata":{"createdBy":"REDACTED","creationTime":"2024-10-30T13:49:37Z","id":"a21c977e-e591-4a9a-8cbb-85474d37c7e8","name":"foo","organizationId":"e9711b20-625f-4b7a-84ee-2fb5ce66389e","projectId":"ede41293-dd82-4449-b804-2dd8b9d2f42f","provisioningStatus":"unknown"},"spec":{"regionId":"f41d1700-a6d8-44e0-87eb-f88c9ee91002"}}

Created okay... returns an object, so we can assume auditing is working...

[Wed 30 Oct 14:00:58 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/securitygroups | jq
[
  {
    "metadata": {
      "createdBy": "REDACTED",
      "creationTime": "2024-10-30T13:49:37Z",
      "id": "a21c977e-e591-4a9a-8cbb-85474d37c7e8",
      "name": "foo",
      "organizationId": "e9711b20-625f-4b7a-84ee-2fb5ce66389e",
      "projectId": "ede41293-dd82-4449-b804-2dd8b9d2f42f",
      "provisioningStatus": "provisioned"
    },
    "spec": {
      "regionId": "f41d1700-a6d8-44e0-87eb-f88c9ee91002"
    }
  }
]
[Wed 30 Oct 14:01:01 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application kubectl get openstacksecuritygroups.region.unikorn-cloud.org -A  -o yaml
apiVersion: v1
items:
- apiVersion: region.unikorn-cloud.org/v1alpha1
  kind: OpenstackSecurityGroup
  metadata:
    annotations:
      unikorn-cloud.org/creator: [email protected]
    creationTimestamp: "2024-10-30T13:56:38Z"
    generation: 1
    labels:
      regions.unikorn-cloud.org/identity-id: bb099525-9c5f-4423-9970-119d9dbfb797
      regions.unikorn-cloud.org/region-id: f41d1700-a6d8-44e0-87eb-f88c9ee91002
      regions.unikorn-cloud.org/security-group-id: a21c977e-e591-4a9a-8cbb-85474d37c7e8
      unikorn-cloud.org/name: foo
      unikorn-cloud.org/organization: e9711b20-625f-4b7a-84ee-2fb5ce66389e
      unikorn-cloud.org/project: ede41293-dd82-4449-b804-2dd8b9d2f42f
    name: a21c977e-e591-4a9a-8cbb-85474d37c7e8
    namespace: unikorn-region
    resourceVersion: "7063707"
    uid: 3aae1cab-2c1d-4273-a456-9f6f1f3ba357
  spec:
    securityGroupID: 78a8f899-70ae-43f5-aab0-cf98f53b5da3
  status: {}
kind: List
metadata:
  resourceVersion: ""

API list works, objects look in order...

Note

The API doesn't actually return the identity the resource is linked to (and neither does the physical network for that matter, I shall swing back around and work out how to do this later.

[Wed 30 Oct 14:03:09 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application openstack security group show 78a8f899-70ae-43f5-aab0-cf98f53b5da3
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field           | Value                                                                                                                                                                            |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| created_at      | 2024-10-30T13:56:38Z                                                                                                                                                             |
| description     | unikorn managed security group                                                                                                                                                   |
| id              | 78a8f899-70ae-43f5-aab0-cf98f53b5da3                                                                                                                                             |
| name            | a21c977e-e591-4a9a-8cbb-85474d37c7e8                                                                                                                                             |
| project_id      | 0f6c6d0bc01a4e9a8fb61dcd0fa19bc8                                                                                                                                                 |
| revision_number | 1                                                                                                                                                                                |
| rules           | created_at='2024-10-30T13:56:38Z', direction='egress', ethertype='IPv6', id='bb88a2d4-24b2-47c1-95d8-7d2fdbcad0b5', standard_attr_id='210759', updated_at='2024-10-30T13:56:38Z' |
|                 | created_at='2024-10-30T13:56:38Z', direction='egress', ethertype='IPv4', id='ea81026f-7ad1-4ba7-8077-0e6d47e26a03', standard_attr_id='210756', updated_at='2024-10-30T13:56:38Z' |
| stateful        | True                                                                                                                                                                             |
| tags            | []                                                                                                                                                                               |
| updated_at      | 2024-10-30T13:56:38Z                                                                                                                                                             |
+-----------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

OpenStack looks happy. I can confirm that these rules are in place implicitly via defaults... on to rules...

@spjmurray
Copy link
Member

[Wed 30 Oct 14:04:14 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups/a21c977e-e591-4a9a-8cbb-85474d37c7e8/rules 
[]

This doesn't return any defaults, good good!

[Wed 30 Oct 14:14:38 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups/a21c977e-e591-4a9a-8cbb-85474d37c7e8/rules -X POST -H 'Content-Type: application/json' -d '{"metadata":{"name":"dns","description":"domain name service"}}'
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx</center>
</body>
</html>

Oh dear a crash...

github.com/unikorn-cloud/region/pkg/handler.(*Handler).generateSecurityGroupRule(0xc000032cf0, {0x1ebf4e8?, 0xc000543650?}, {0xc000ae447b, 0x24}, {0xc000ae44a9, 0x24}, 0xc001859a20, 0xc001859ce0, 0xc001c30ee0)
	github.com/unikorn-cloud/region/pkg/handler/handler.go:1300 +0x11d

So that should have resulted in an error from OpenAPI because the spec is missing... once fixed we get...

[Wed 30 Oct 14:14:41 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups/a21c977e-e591-4a9a-8cbb-85474d37c7e8/rules -X POST -H 'Content-Type: application/json' -d '{"metadata":{"name":"dns","description":"domain name service"}}' | jq
{
  "error": "invalid_request",
  "error_description": "request body invalid"
}

Trying the following....

[Wed 30 Oct 14:21:16 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups/a21c977e-e591-4a9a-8cbb-85474d37c7e8/rules -X POST -H 'Content-Type: application/json' -d '{"metadata":{"name":"dns","description":"domain name service"},"spec":{"direction":"ingress","protocol":"udp","port":{"number":53},"cidr":"0.0.0.0/0"}}' | jq
{
  "metadata": {
    "createdBy": "[email protected]",
    "creationTime": "2024-10-30T14:21:30Z",
    "description": "domain name service",
    "id": "cc68dcb9-9b59-43c8-b7c7-75b38c350813",
    "name": "dns",
    "organizationId": "e9711b20-625f-4b7a-84ee-2fb5ce66389e",
    "projectId": "ede41293-dd82-4449-b804-2dd8b9d2f42f",
    "provisioningStatus": "unknown"
  },
  "spec": {
    "cidr": "0.0.0.0/0",
    "direction": "ingress",
    "port": {
      "number": 53
    },
    "protocol": "udp"
  }
}

looking good... ah yeah...

[Wed 30 Oct 14:23:37 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application openstack security group show 78a8f899-70ae-43f5-aab0-cf98f53b5da3
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Field           | Value                                                                                                                                                                                                                                                                                                                                                     |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| created_at      | 2024-10-30T13:56:38Z                                                                                                                                                                                                                                                                                                                                      |
| description     | unikorn managed security group                                                                                                                                                                                                                                                                                                                            |
| id              | 78a8f899-70ae-43f5-aab0-cf98f53b5da3                                                                                                                                                                                                                                                                                                                      |
| name            | a21c977e-e591-4a9a-8cbb-85474d37c7e8                                                                                                                                                                                                                                                                                                                      |
| project_id      | 0f6c6d0bc01a4e9a8fb61dcd0fa19bc8                                                                                                                                                                                                                                                                                                                          |
| revision_number | 2                                                                                                                                                                                                                                                                                                                                                         |
| rules           | created_at='2024-10-30T14:23:22Z', description='unikorn managed security group rule', direction='ingress', ethertype='IPv4', id='5af05869-66f3-4113-8417-fa34eea861fb', normalized_cidr='0.0.0.0/0', port_range_max='53', port_range_min='53', protocol='udp', remote_ip_prefix='0.0.0.0/0', standard_attr_id='210855', updated_at='2024-10-30T14:23:22Z' |
|                 | created_at='2024-10-30T13:56:38Z', direction='egress', ethertype='IPv6', id='bb88a2d4-24b2-47c1-95d8-7d2fdbcad0b5', standard_attr_id='210759', updated_at='2024-10-30T13:56:38Z'                                                                                                                                                                          |
|                 | created_at='2024-10-30T13:56:38Z', direction='egress', ethertype='IPv4', id='ea81026f-7ad1-4ba7-8077-0e6d47e26a03', standard_attr_id='210756', updated_at='2024-10-30T13:56:38Z'                                                                                                                                                                          |
| stateful        | True                                                                                                                                                                                                                                                                                                                                                      |
| tags            | []                                                                                                                                                                                                                                                                                                                                                        |
| updated_at      | 2024-10-30T14:23:22Z                                                                                                                                                                                                                                                                                                                                      |
+-----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Now let's try delete the security group and see what happens 👿 ...

[Wed 30 Oct 14:25:28 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application curl -s -k -H "Authorization: Bearer ${AT}" https://region.spjmurray.co.uk/api/v1/organizations/e9711b20-625f-4b7a-84ee-2fb5ce66389e/projects/ede41293-dd82-4449-b804-2dd8b9d2f42f/identities/bb099525-9c5f-4423-9970-119d9dbfb797/securitygroups/a21c977e-e591-4a9a-8cbb-85474d37c7e8 -X DELETE
[Wed 30 Oct 14:29:44 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application kubectl get securitygroups.region.unikorn-cloud.org -A 
NAMESPACE        NAME                                   STATUS           AGE
unikorn-region   a21c977e-e591-4a9a-8cbb-85474d37c7e8   Deprovisioning   40m
[Wed 30 Oct 14:30:12 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application kubectl get securitygrouprules.region.unikorn-cloud.org -A 
No resources found
[Wed 30 Oct 14:30:17 GMT 2024] simon@symphony ~/src/github.com/unikorn-cloud/application kubectl get securitygroups.region.unikorn-cloud.org -A 
No resources found

beautiful so far...

@spjmurray
Copy link
Member

To this point I needed to:

  • Add Docker containers
  • Add Helm templates
  • Apply a couple patches

Here's the gist so far... https://gist.github.com/spjmurray/edc1d1036b5f4083a960143409092ad1

Copy link
Member

@spjmurray spjmurray left a comment

Choose a reason for hiding this comment

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

See the earlier comments from my acceptance testing, apply that patch and I'll continue onward...

One thing I will say is while the deleting the security group does cascade and delete the rules, you may want to consider my next test which will be deleting the entire identity and my expectation that the security groups will also disappear 👿 Now you appear to have handled the owner reference bit (cascading deletion), but the problem will be race conditions. If the user/project is deleted before the security group, then it'll get very stuck. See how physical networks are handled in pkg/provisioners/managers/identity/provisioner.go.

Also, f***ing great work, I've only got the 4 big files left to review, and they look (superficially) rather nice to gaze at!

@spjmurray
Copy link
Member

Thanks will get on it first thing tomorrow, got a bit bogged down today, there's a merge conflict with the schema you need to sort, I did an upgrade of the tooling, so basically just delete the schema file and run make when the git has a panic attack.

@spjmurray
Copy link
Member

Okay, add this and you'll get a 👍🏻 Seems good enough for now!

diff --git a/charts/region/templates/identity-controller/clusterrole.yaml b/charts/region/templates/identity-controller/clusterrole.yaml
index 65b7fb1..9987ccf 100644
--- a/charts/region/templates/identity-controller/clusterrole.yaml
+++ b/charts/region/templates/identity-controller/clusterrole.yaml
@@ -37,6 +37,7 @@ rules:
   resources:
   - quotas
   - physicalnetworks
+  - securitygroups
   verbs:
   - list
   - watch

Copy link
Member

@spjmurray spjmurray left a comment

Choose a reason for hiding this comment

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

Appears to what it claims, so let's do this!

@spjmurray spjmurray merged commit 204e54a into unikorn-cloud:main Nov 1, 2024
2 checks passed
@nsricardor nsricardor deleted the feature/add-security-group-crd branch November 1, 2024 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants