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 }