github.com/khulnasoft-lab/defsec@v1.0.5-0.20230827010352-5e9f46893d95/internal/adapters/cloud/aws/redshift/adapt.go (about)

     1  package redshift
     2  
     3  import (
     4  	"strings"
     5  
     6  	api "github.com/aws/aws-sdk-go-v2/service/redshift"
     7  	"github.com/aws/aws-sdk-go-v2/service/redshift/types"
     8  	"github.com/khulnasoft-lab/defsec/internal/adapters/cloud/aws"
     9  	"github.com/khulnasoft-lab/defsec/pkg/concurrency"
    10  	"github.com/khulnasoft-lab/defsec/pkg/providers/aws/redshift"
    11  	"github.com/khulnasoft-lab/defsec/pkg/state"
    12  	defsecTypes "github.com/khulnasoft-lab/defsec/pkg/types"
    13  )
    14  
    15  type adapter struct {
    16  	*aws.RootAdapter
    17  	api *api.Client
    18  }
    19  
    20  func init() {
    21  	aws.RegisterServiceAdapter(&adapter{})
    22  }
    23  
    24  func (a *adapter) Provider() string {
    25  	return "aws"
    26  }
    27  
    28  func (a *adapter) Name() string {
    29  	return "redshift"
    30  }
    31  
    32  func (a *adapter) Adapt(root *aws.RootAdapter, state *state.State) error {
    33  
    34  	a.RootAdapter = root
    35  	a.api = api.NewFromConfig(root.SessionConfig())
    36  	var err error
    37  
    38  	state.AWS.Redshift.Clusters, err = a.getClusters()
    39  	if err != nil {
    40  		return err
    41  	}
    42  
    43  	state.AWS.Redshift.ReservedNodes, err = a.getReservedNodes()
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	state.AWS.Redshift.ClusterParameters, err = a.getParameters()
    49  	if err != nil {
    50  		return err
    51  	}
    52  
    53  	// this can error is classic resources are used where disabled
    54  	state.AWS.Redshift.SecurityGroups, err = a.getSecurityGroups()
    55  	if err != nil {
    56  		a.Debug("Failed to adapt security groups: %s", err)
    57  		return nil
    58  	}
    59  
    60  	return nil
    61  }
    62  
    63  func (a *adapter) getClusters() ([]redshift.Cluster, error) {
    64  
    65  	a.Tracker().SetServiceLabel("Discovering clusters...")
    66  
    67  	var apiClusters []types.Cluster
    68  	var input api.DescribeClustersInput
    69  	for {
    70  		output, err := a.api.DescribeClusters(a.Context(), &input)
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  		apiClusters = append(apiClusters, output.Clusters...)
    75  		a.Tracker().SetTotalResources(len(apiClusters))
    76  		if output.Marker == nil {
    77  			break
    78  		}
    79  		input.Marker = output.Marker
    80  	}
    81  
    82  	a.Tracker().SetServiceLabel("Adapting clusters...")
    83  	return concurrency.Adapt(apiClusters, a.RootAdapter, a.adaptCluster), nil
    84  }
    85  
    86  func (a *adapter) adaptCluster(apiCluster types.Cluster) (*redshift.Cluster, error) {
    87  
    88  	metadata := a.CreateMetadataFromARN(*apiCluster.ClusterNamespaceArn)
    89  
    90  	output, err := a.api.DescribeLoggingStatus(a.Context(), &api.DescribeLoggingStatusInput{
    91  		ClusterIdentifier: apiCluster.ClusterIdentifier,
    92  	})
    93  	if err != nil {
    94  		output = nil
    95  	}
    96  
    97  	var loggingenabled bool
    98  	if output != nil {
    99  		loggingenabled = output.LoggingEnabled
   100  	}
   101  
   102  	var kmsKeyId string
   103  	if apiCluster.KmsKeyId != nil {
   104  		kmsKeyId = *apiCluster.KmsKeyId
   105  	}
   106  
   107  	var subnetGroupName string
   108  	if apiCluster.ClusterSubnetGroupName != nil {
   109  		subnetGroupName = *apiCluster.ClusterSubnetGroupName
   110  	}
   111  
   112  	var port int
   113  	if apiCluster.Endpoint != nil {
   114  		port = int(apiCluster.Endpoint.Port)
   115  	}
   116  
   117  	return &redshift.Cluster{
   118  		Metadata:                         metadata,
   119  		ClusterIdentifier:                defsecTypes.String(*apiCluster.ClusterIdentifier, metadata),
   120  		AllowVersionUpgrade:              defsecTypes.Bool(apiCluster.AllowVersionUpgrade, metadata),
   121  		NumberOfNodes:                    defsecTypes.Int(int(apiCluster.NumberOfNodes), metadata),
   122  		NodeType:                         defsecTypes.String(*apiCluster.NodeType, metadata),
   123  		PubliclyAccessible:               defsecTypes.Bool(apiCluster.PubliclyAccessible, metadata),
   124  		VpcId:                            defsecTypes.String(*apiCluster.VpcId, metadata),
   125  		MasterUsername:                   defsecTypes.String(*apiCluster.MasterUsername, metadata),
   126  		AutomatedSnapshotRetentionPeriod: defsecTypes.Int(int(apiCluster.ManualSnapshotRetentionPeriod), metadata),
   127  		LoggingEnabled:                   defsecTypes.Bool(loggingenabled, metadata),
   128  		EndPoint: redshift.EndPoint{
   129  			Metadata: metadata,
   130  			Port:     defsecTypes.Int(port, metadata),
   131  		},
   132  		Encryption: redshift.Encryption{
   133  			Metadata: metadata,
   134  			Enabled:  defsecTypes.Bool(apiCluster.Encrypted, metadata),
   135  			KMSKeyID: defsecTypes.String(kmsKeyId, metadata),
   136  		},
   137  		SubnetGroupName: defsecTypes.String(subnetGroupName, metadata),
   138  	}, nil
   139  }
   140  
   141  func (a *adapter) getSecurityGroups() ([]redshift.SecurityGroup, error) {
   142  
   143  	a.Tracker().SetServiceLabel("Discovering security groups...")
   144  
   145  	var apiGroups []types.ClusterSecurityGroup
   146  	var input api.DescribeClusterSecurityGroupsInput
   147  	for {
   148  		output, err := a.api.DescribeClusterSecurityGroups(a.Context(), &input)
   149  		if err != nil {
   150  			return nil, err
   151  		}
   152  		apiGroups = append(apiGroups, output.ClusterSecurityGroups...)
   153  		a.Tracker().SetTotalResources(len(apiGroups))
   154  		if output.Marker == nil {
   155  			break
   156  		}
   157  		input.Marker = output.Marker
   158  	}
   159  
   160  	a.Tracker().SetServiceLabel("Adapting security groups...")
   161  	return concurrency.Adapt(apiGroups, a.RootAdapter, a.adaptSecurityGroup), nil
   162  }
   163  
   164  func (a *adapter) adaptSecurityGroup(apiSG types.ClusterSecurityGroup) (*redshift.SecurityGroup, error) {
   165  
   166  	metadata := a.CreateMetadata("securitygroup:" + *apiSG.ClusterSecurityGroupName)
   167  
   168  	description := defsecTypes.StringDefault("", metadata)
   169  	if apiSG.Description != nil {
   170  		description = defsecTypes.String(*apiSG.Description, metadata)
   171  	}
   172  
   173  	return &redshift.SecurityGroup{
   174  		Metadata:    metadata,
   175  		Description: description,
   176  	}, nil
   177  }
   178  
   179  func (a *adapter) getReservedNodes() ([]redshift.ReservedNode, error) {
   180  
   181  	a.Tracker().SetServiceLabel("Discovering reserved nodes...")
   182  
   183  	var apiReservednodes []types.ReservedNode
   184  	var input api.DescribeReservedNodesInput
   185  	for {
   186  		output, err := a.api.DescribeReservedNodes(a.Context(), &input)
   187  		if err != nil {
   188  			return nil, err
   189  		}
   190  		apiReservednodes = append(apiReservednodes, output.ReservedNodes...)
   191  		a.Tracker().SetTotalResources(len(apiReservednodes))
   192  		if output.Marker == nil {
   193  			break
   194  		}
   195  		input.Marker = output.Marker
   196  	}
   197  
   198  	a.Tracker().SetServiceLabel("Adapting reserved node ...")
   199  	return concurrency.Adapt(apiReservednodes, a.RootAdapter, a.adaptnode), nil
   200  }
   201  
   202  func (a *adapter) adaptnode(node types.ReservedNode) (*redshift.ReservedNode, error) {
   203  	metadata := a.CreateMetadata(*node.ReservedNodeId)
   204  	return &redshift.ReservedNode{
   205  		Metadata: metadata,
   206  		NodeType: defsecTypes.String(*node.NodeType, metadata),
   207  	}, nil
   208  }
   209  
   210  func (a *adapter) getParameters() ([]redshift.ClusterParameter, error) {
   211  
   212  	a.Tracker().SetServiceLabel("Discovering cluster parameters ...")
   213  
   214  	var apiClusters []types.Parameter
   215  	var input api.DescribeClusterParameterGroupsInput
   216  	output, err := a.api.DescribeClusterParameterGroups(a.Context(), &input)
   217  	if err != nil {
   218  		return nil, err
   219  	}
   220  	for _, group := range output.ParameterGroups {
   221  		groupname := *group.ParameterGroupName
   222  		if !strings.HasPrefix(groupname, "default.redshift") {
   223  			output, err := a.api.DescribeClusterParameters(a.Context(), &api.DescribeClusterParametersInput{
   224  				ParameterGroupName: group.ParameterGroupName,
   225  			})
   226  			if err != nil {
   227  				return nil, err
   228  			}
   229  			apiClusters = append(apiClusters, output.Parameters...)
   230  			a.Tracker().SetTotalResources(len(apiClusters))
   231  			if output.Marker == nil {
   232  				break
   233  			}
   234  			input.Marker = output.Marker
   235  		}
   236  
   237  	}
   238  
   239  	a.Tracker().SetServiceLabel("Adapting cluster parameters...")
   240  	return concurrency.Adapt(apiClusters, a.RootAdapter, a.adaptParameter), nil
   241  }
   242  
   243  func (a *adapter) adaptParameter(parameter types.Parameter) (*redshift.ClusterParameter, error) {
   244  
   245  	metadata := a.CreateMetadata(*parameter.ParameterName)
   246  
   247  	return &redshift.ClusterParameter{
   248  		Metadata:       metadata,
   249  		ParameterName:  defsecTypes.String(*parameter.ParameterName, metadata),
   250  		ParameterValue: defsecTypes.String(*parameter.ParameterValue, metadata),
   251  	}, nil
   252  
   253  }