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 support for NSG chaining #323

Merged
merged 3 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
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
10 changes: 5 additions & 5 deletions api/v1beta2/ocimanagedcluster_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func (c *OCIManagedCluster) GetControlPlaneEndpointDefaultEgressRules() []Egress
EgressSecurityRule: EgressSecurityRule{
Description: common.String("Allow Kubernetes API endpoint to communicate with OKE."),
Protocol: common.String("6"),
DestinationType: EgressSecurityRuleSourceTypeServiceCidrBlock,
DestinationType: EgressSecurityRuleDestinationTypeServiceCidrBlock,
shyamradhakrishnan marked this conversation as resolved.
Show resolved Hide resolved
},
},
{
Expand All @@ -322,7 +322,7 @@ func (c *OCIManagedCluster) GetControlPlaneEndpointDefaultEgressRules() []Egress
Type: common.Int(3),
Code: common.Int(4),
},
DestinationType: EgressSecurityRuleSourceTypeServiceCidrBlock,
DestinationType: EgressSecurityRuleDestinationTypeServiceCidrBlock,
},
},
{
Expand Down Expand Up @@ -413,7 +413,7 @@ func (c *OCIManagedCluster) GetWorkerDefaultEgressRules() []EgressSecurityRuleFo
EgressSecurityRule: EgressSecurityRule{
Description: common.String("Allow worker nodes to communicate with OKE."),
Protocol: common.String("6"),
DestinationType: EgressSecurityRuleSourceTypeServiceCidrBlock,
DestinationType: EgressSecurityRuleDestinationTypeServiceCidrBlock,
},
},
{
Expand Down Expand Up @@ -502,7 +502,7 @@ func (c *OCIManagedCluster) GetPodDefaultEgressRules() []EgressSecurityRuleForNS
EgressSecurityRule: EgressSecurityRule{
Description: common.String("Allow worker nodes to communicate with OCI Services."),
Protocol: common.String("6"),
DestinationType: EgressSecurityRuleSourceTypeServiceCidrBlock,
DestinationType: EgressSecurityRuleDestinationTypeServiceCidrBlock,
},
},
{
Expand All @@ -513,7 +513,7 @@ func (c *OCIManagedCluster) GetPodDefaultEgressRules() []EgressSecurityRuleForNS
Type: common.Int(3),
Code: common.Int(4),
},
DestinationType: EgressSecurityRuleSourceTypeServiceCidrBlock,
DestinationType: EgressSecurityRuleDestinationTypeServiceCidrBlock,
},
},
{
Expand Down
10 changes: 8 additions & 2 deletions api/v1beta2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,8 @@ type EgressSecurityRule struct {
// * `SERVICE_CIDR_BLOCK`: If the rule's `destination` is the `cidrBlock` value for a
// Service (the rule is for traffic destined for a
// particular `Service` through a service gateway).
// * `NETWORK_SECURITY_GROUP`: If the rule's `destination` is the OCID (https://docs.cloud.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a
// NetworkSecurityGroup.
DestinationType EgressSecurityRuleDestinationTypeEnum `json:"destinationType,omitempty"`

IcmpOptions *IcmpOptions `json:"icmpOptions,omitempty"`
Expand Down Expand Up @@ -726,6 +728,8 @@ type IngressSecurityRule struct {
// * `SERVICE_CIDR_BLOCK`: If the rule's `source` is the `cidrBlock` value for a
// Service (the rule is for traffic coming from a
// particular `Service` through a service gateway).
// * `NETWORK_SECURITY_GROUP`: If the rule's `destination` is the OCID (https://docs.cloud.oracle.com/iaas/Content/General/Concepts/identifiers.htm) of a
// NetworkSecurityGroup.
SourceType IngressSecurityRuleSourceTypeEnum `json:"sourceType,omitempty"`

TcpOptions *TcpOptions `json:"tcpOptions,omitempty"`
Expand Down Expand Up @@ -753,6 +757,7 @@ type IngressSecurityRuleSourceTypeEnum string
const (
IngressSecurityRuleSourceTypeCidrBlock IngressSecurityRuleSourceTypeEnum = "CIDR_BLOCK"
IngressSecurityRuleSourceTypeServiceCidrBlock IngressSecurityRuleSourceTypeEnum = "SERVICE_CIDR_BLOCK"
IngressSecurityRuleSourceTypeNSG IngressSecurityRuleSourceTypeEnum = "NETWORK_SECURITY_GROUP"
)

// UdpOptions Optional and valid only for UDP. Use to specify particular destination ports for UDP rules.
Expand Down Expand Up @@ -802,8 +807,9 @@ type PortRange struct {

const (
// EgressSecurityRuleDestinationTypeCidrBlock is the contant for CIDR block security rule destination type
EgressSecurityRuleDestinationTypeCidrBlock EgressSecurityRuleDestinationTypeEnum = "CIDR_BLOCK"
EgressSecurityRuleSourceTypeServiceCidrBlock EgressSecurityRuleDestinationTypeEnum = "SERVICE_CIDR_BLOCK"
EgressSecurityRuleDestinationTypeCidrBlock EgressSecurityRuleDestinationTypeEnum = "CIDR_BLOCK"
EgressSecurityRuleDestinationTypeServiceCidrBlock EgressSecurityRuleDestinationTypeEnum = "SERVICE_CIDR_BLOCK"
EgressSecurityRuleDestinationTypeNSG EgressSecurityRuleDestinationTypeEnum = "NETWORK_SECURITY_GROUP"
)

type EgressSecurityRuleDestinationTypeEnum string
Expand Down
70 changes: 49 additions & 21 deletions cloud/scope/nsg_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,6 @@ func (s *ClusterScope) ReconcileNSG(ctx context.Context) error {
}
s.Logger.Info("Successfully updated network security list", "nsg", nsgOCID)
}
s.adjustNSGRulesSpec(desiredNSG)
isNSGUpdated, err := s.UpdateNSGSecurityRulesIfNeeded(ctx, *desiredNSG, nsg)
if err != nil {
return err
}
if !isNSGUpdated {
s.Logger.Info("No Reconciliation Required for Network Security Group", "nsg", *desiredNSG.ID)
}
continue
}
s.Logger.Info("Creating the network security list")
Expand All @@ -64,16 +56,22 @@ func (s *ClusterScope) ReconcileNSG(ctx context.Context) error {
}
s.Logger.Info("Created the nsg", "nsg", nsgID)
desiredNSG.ID = nsgID
s.adjustNSGRulesSpec(desiredNSG)
err = s.AddNSGSecurityRules(ctx, desiredNSG.ID, desiredNSG.IngressRules, desiredNSG.EgressRules)

}
for _, desiredNSG := range desiredNSGs.List {
s.adjustNSGRulesSpec(desiredNSG, desiredNSGs.List)
isNSGUpdated, err := s.UpdateNSGSecurityRulesIfNeeded(ctx, *desiredNSG, desiredNSG.ID)
if err != nil {
return err
}
if !isNSGUpdated {
s.Logger.Info("No Reconciliation Required for Network Security Group", "nsg", *desiredNSG.ID)
}
}
return nil
}

func (s *ClusterScope) adjustNSGRulesSpec(desiredNSG *infrastructurev1beta2.NSG) {
func (s *ClusterScope) adjustNSGRulesSpec(desiredNSG *infrastructurev1beta2.NSG, nsgList []*infrastructurev1beta2.NSG) {
ingressRules := make([]infrastructurev1beta2.IngressSecurityRuleForNSG, 0)
for _, ingressRule := range desiredNSG.IngressRules {
if ingressRule.SourceType == infrastructurev1beta2.IngressSecurityRuleSourceTypeServiceCidrBlock {
Expand All @@ -84,7 +82,7 @@ func (s *ClusterScope) adjustNSGRulesSpec(desiredNSG *infrastructurev1beta2.NSG)
desiredNSG.IngressRules = ingressRules
egressRules := make([]infrastructurev1beta2.EgressSecurityRuleForNSG, 0)
for _, egressRule := range desiredNSG.EgressRules {
if egressRule.DestinationType == infrastructurev1beta2.EgressSecurityRuleSourceTypeServiceCidrBlock {
if egressRule.DestinationType == infrastructurev1beta2.EgressSecurityRuleDestinationTypeServiceCidrBlock {
egressRule.Destination = common.String(fmt.Sprintf("all-%s-services-in-oracle-services-network", strings.ToLower(s.RegionKey)))
}
egressRules = append(egressRules, egressRule)
Expand Down Expand Up @@ -171,19 +169,19 @@ func (s *ClusterScope) IsNSGEqual(actual *core.NetworkSecurityGroup, desired inf

// UpdateNSGSecurityRulesIfNeeded updates NSG rules if required by comparing actual and desired.
func (s *ClusterScope) UpdateNSGSecurityRulesIfNeeded(ctx context.Context, desired infrastructurev1beta2.NSG,
actual *core.NetworkSecurityGroup) (bool, error) {
nsgId *string) (bool, error) {
var ingressRulesToAdd []infrastructurev1beta2.IngressSecurityRuleForNSG
var egressRulesToAdd []infrastructurev1beta2.EgressSecurityRuleForNSG
var securityRulesToRemove []string
var isNSGUpdated bool
listSecurityRulesResponse, err := s.VCNClient.ListNetworkSecurityGroupSecurityRules(ctx, core.ListNetworkSecurityGroupSecurityRulesRequest{
NetworkSecurityGroupId: actual.Id,
NetworkSecurityGroupId: nsgId,
})
if err != nil {
s.Logger.Error(err, "failed to reconcile the network security group, failed to list security rules")
return isNSGUpdated, errors.Wrap(err, "failed to reconcile the network security group, failed to list security rules")
}
ingressRules, egressRules := generateSpecFromSecurityRules(listSecurityRulesResponse.Items)
ingressRules, egressRules := s.generateSpecFromSecurityRules(listSecurityRulesResponse.Items, nsgId)

for i, ingressRule := range desired.IngressRules {
if ingressRule.IsStateless == nil {
Expand Down Expand Up @@ -255,7 +253,7 @@ func (s *ClusterScope) UpdateNSGSecurityRulesIfNeeded(ctx context.Context, desir
s.Logger.Error(err, "failed to reconcile the network security group, failed to add security rules")
return isNSGUpdated, err
}
s.Logger.Info("Successfully added missing rules in NSG", "nsg", *actual.Id)
s.Logger.Info("Successfully added missing rules in NSG", "nsg", *nsgId)
}
if len(securityRulesToRemove) > 0 {
isNSGUpdated = true
Expand All @@ -269,7 +267,7 @@ func (s *ClusterScope) UpdateNSGSecurityRulesIfNeeded(ctx context.Context, desir
s.Logger.Error(err, "failed to reconcile the network security group, failed to remove security rules")
return isNSGUpdated, err
}
s.Logger.Info("Successfully deleted rules in NSG", "nsg", *actual.Id)
s.Logger.Info("Successfully deleted rules in NSG", "nsg", *nsgId)
}
return isNSGUpdated, nil
}
Expand Down Expand Up @@ -315,6 +313,9 @@ func (s *ClusterScope) generateAddSecurityRuleFromSpec(ingressRules []infrastruc
TcpOptions: tcpOptions,
UdpOptions: udpOptions,
}
if ingressRule.SourceType == infrastructurev1beta2.IngressSecurityRuleSourceTypeNSG {
secRule.Source = getNsgIdFromName(ingressRule.Source, s.GetNSGSpec())
}
securityRules = append(securityRules, secRule)
}
for _, egressRule := range egressRules {
Expand All @@ -335,15 +336,15 @@ func (s *ClusterScope) generateAddSecurityRuleFromSpec(ingressRules []infrastruc
TcpOptions: tcpOptions,
UdpOptions: udpOptions,
}
securityRules = append(securityRules, secRule)
if egressRule.DestinationType == "SERVICE_CIDR_BLOCK" {
secRule.Destination = common.String(fmt.Sprintf("all-%s-services-in-oracle-services-network", strings.ToLower(s.RegionKey)))
if egressRule.DestinationType == infrastructurev1beta2.EgressSecurityRuleDestinationTypeNSG {
secRule.Destination = getNsgIdFromName(egressRule.Destination, s.GetNSGSpec())
}
securityRules = append(securityRules, secRule)
}
return securityRules
}

func generateSpecFromSecurityRules(rules []core.SecurityRule) (map[string]infrastructurev1beta2.IngressSecurityRuleForNSG, map[string]infrastructurev1beta2.EgressSecurityRuleForNSG) {
func (s *ClusterScope) generateSpecFromSecurityRules(rules []core.SecurityRule, nsgId *string) (map[string]infrastructurev1beta2.IngressSecurityRuleForNSG, map[string]infrastructurev1beta2.EgressSecurityRuleForNSG) {
var ingressRules = make(map[string]infrastructurev1beta2.IngressSecurityRuleForNSG)
var egressRules = make(map[string]infrastructurev1beta2.EgressSecurityRuleForNSG)
var stateless *bool
Expand All @@ -368,6 +369,9 @@ func generateSpecFromSecurityRules(rules []core.SecurityRule) (map[string]infras
Description: rule.Description,
},
}
if rule.SourceType == core.SecurityRuleSourceTypeNetworkSecurityGroup {
ingressRule.IngressSecurityRule.Source = getNsgNameFromId(rule.Source, s.GetNSGSpec())
}
ingressRules[*rule.Id] = ingressRule
case core.SecurityRuleDirectionEgress:
egressRule := infrastructurev1beta2.EgressSecurityRuleForNSG{
Expand All @@ -382,6 +386,9 @@ func generateSpecFromSecurityRules(rules []core.SecurityRule) (map[string]infras
Description: rule.Description,
},
}
if rule.DestinationType == core.SecurityRuleDestinationTypeNetworkSecurityGroup {
egressRule.EgressSecurityRule.Destination = getNsgNameFromId(rule.Destination, s.GetNSGSpec())
}
egressRules[*rule.Id] = egressRule
}
}
Expand Down Expand Up @@ -465,3 +472,24 @@ func getProtocolOptionsForSpec(icmp *core.IcmpOptions, tcp *core.TcpOptions, udp
}
return icmpOptions, tcpOptions, udpOptions
}

func getNsgIdFromName(nsgName *string, list []*infrastructurev1beta2.NSG) *string {
for _, nsg := range list {
if nsg.Name == *nsgName {
return nsg.ID
}
}
return nil
}

func getNsgNameFromId(nsgId *string, list []*infrastructurev1beta2.NSG) *string {
if nsgId == nil {
return nil
}
for _, nsg := range list {
if reflect.DeepEqual(nsg.ID, nsgId) {
return &nsg.Name
}
}
return nil
}
Loading