2021-01-20 13:01:57 +00:00
package remote
import (
"fmt"
2021-02-11 11:21:49 +00:00
"strings"
2021-01-20 13:01:57 +00:00
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/cloudskiff/driftctl/pkg/alerter"
2021-03-02 10:39:14 +00:00
"github.com/cloudskiff/driftctl/pkg/remote/aws"
remoteerror "github.com/cloudskiff/driftctl/pkg/remote/error"
"github.com/cloudskiff/driftctl/pkg/remote/github"
2021-02-12 21:35:21 +00:00
"github.com/sirupsen/logrus"
2021-01-20 13:01:57 +00:00
)
2021-07-28 14:30:22 +00:00
type ScanningPhase int
const (
EnumerationPhase ScanningPhase = iota
DetailsFetchingPhase
)
type RemoteAccessDeniedAlert struct {
message string
provider string
scanningPhase ScanningPhase
2021-02-12 21:35:21 +00:00
}
2021-07-28 14:30:22 +00:00
func NewRemoteAccessDeniedAlert ( provider , supplierType , listedTypeError string , scanningPhase ScanningPhase ) * RemoteAccessDeniedAlert {
var message string
switch scanningPhase {
case EnumerationPhase :
message = fmt . Sprintf ( "Ignoring %s from drift calculation: Listing %s is forbidden." , supplierType , listedTypeError )
case DetailsFetchingPhase :
message = fmt . Sprintf ( "Ignoring %s from drift calculation: Reading details of %s is forbidden." , supplierType , listedTypeError )
default :
message = fmt . Sprintf ( "Ignoring %s from drift calculation: %s" , supplierType , listedTypeError )
}
return & RemoteAccessDeniedAlert { message , provider , scanningPhase }
2021-02-12 21:35:21 +00:00
}
2021-07-28 14:30:22 +00:00
func ( e * RemoteAccessDeniedAlert ) Message ( ) string {
2021-02-12 21:35:21 +00:00
return e . message
}
2021-07-28 14:30:22 +00:00
func ( e * RemoteAccessDeniedAlert ) ShouldIgnoreResource ( ) bool {
2021-02-12 21:35:21 +00:00
return true
}
2021-07-28 14:30:22 +00:00
func ( e * RemoteAccessDeniedAlert ) GetProviderMessage ( ) string {
var message string
switch e . scanningPhase {
case DetailsFetchingPhase :
message = "It seems that we got access denied exceptions while reading details of resources.\n"
case EnumerationPhase :
fallthrough
default :
message = "It seems that we got access denied exceptions while listing resources.\n"
}
2021-03-02 10:39:14 +00:00
switch e . provider {
case github . RemoteGithubTerraform :
2021-05-12 09:31:00 +00:00
message += "Please be sure that your Github token has the right permissions, check the last up-to-date documentation there: https://docs.driftctl.com/github/policy"
2021-03-02 10:39:14 +00:00
case aws . RemoteAWSTerraform :
2021-05-12 09:31:00 +00:00
message += "The latest minimal read-only IAM policy for driftctl is always available here, please update yours: https://docs.driftctl.com/aws/policy"
2021-03-02 10:39:14 +00:00
default :
return ""
}
return message
}
2021-06-28 09:00:59 +00:00
func HandleResourceEnumerationError ( err error , alerter alerter . AlerterInterface ) error {
2021-07-28 14:30:22 +00:00
listError , ok := err . ( * remoteerror . ResourceScanningError )
2021-01-20 13:01:57 +00:00
if ! ok {
return err
}
2021-03-02 10:39:14 +00:00
rootCause := listError . RootCause ( )
reqerr , ok := rootCause . ( awserr . RequestFailure )
if ok {
return handleAWSError ( alerter , listError , reqerr )
2021-01-20 13:01:57 +00:00
}
2021-07-28 14:30:22 +00:00
if strings . Contains ( rootCause . Error ( ) , "AccessDenied" ) {
sendEnumerationAlert ( aws . RemoteAWSTerraform , alerter , listError )
return nil
}
2021-03-02 10:39:14 +00:00
if strings . HasPrefix (
rootCause . Error ( ) ,
"Your token has not been granted the required scopes to execute this query." ,
) {
sendEnumerationAlert ( github . RemoteGithubTerraform , alerter , listError )
2021-01-20 13:01:57 +00:00
return nil
}
return err
}
2021-03-02 10:39:14 +00:00
2021-07-28 14:30:22 +00:00
func HandleResourceDetailsFetchingError ( err error , alerter alerter . AlerterInterface ) error {
listError , ok := err . ( * remoteerror . ResourceScanningError )
if ! ok {
return err
}
rootCause := listError . RootCause ( )
if strings . HasPrefix ( rootCause . Error ( ) , "AccessDeniedException" ) {
sendDetailsFetchingAlert ( aws . RemoteAWSTerraform , alerter , listError )
return nil
}
if strings . Contains ( rootCause . Error ( ) , "AccessDenied" ) {
sendDetailsFetchingAlert ( aws . RemoteAWSTerraform , alerter , listError )
return nil
}
if strings . Contains ( rootCause . Error ( ) , "AuthorizationError" ) {
sendDetailsFetchingAlert ( aws . RemoteAWSTerraform , alerter , listError )
return nil
}
return err
}
func handleAWSError ( alerter alerter . AlerterInterface , listError * remoteerror . ResourceScanningError , reqerr awserr . RequestFailure ) error {
2021-03-02 10:39:14 +00:00
if reqerr . StatusCode ( ) == 403 || ( reqerr . StatusCode ( ) == 400 && strings . Contains ( reqerr . Code ( ) , "AccessDenied" ) ) {
sendEnumerationAlert ( aws . RemoteAWSTerraform , alerter , listError )
return nil
}
return reqerr
}
2021-07-28 14:30:22 +00:00
func sendEnumerationAlert ( provider string , alerter alerter . AlerterInterface , listError * remoteerror . ResourceScanningError ) {
logrus . WithFields ( logrus . Fields {
"supplier_type" : listError . SupplierType ( ) ,
"listed_type" : listError . ListedTypeError ( ) ,
} ) . Debugf ( "Got an access denied error" )
alerter . SendAlert ( listError . SupplierType ( ) , NewRemoteAccessDeniedAlert ( provider , listError . SupplierType ( ) , listError . ListedTypeError ( ) , EnumerationPhase ) )
}
func sendDetailsFetchingAlert ( provider string , alerter alerter . AlerterInterface , listError * remoteerror . ResourceScanningError ) {
2021-03-02 10:39:14 +00:00
logrus . WithFields ( logrus . Fields {
"supplier_type" : listError . SupplierType ( ) ,
"listed_type" : listError . ListedTypeError ( ) ,
} ) . Debugf ( "Got an access denied error" )
2021-07-28 14:30:22 +00:00
alerter . SendAlert ( listError . SupplierType ( ) , NewRemoteAccessDeniedAlert ( provider , listError . SupplierType ( ) , listError . ListedTypeError ( ) , DetailsFetchingPhase ) )
2021-03-02 10:39:14 +00:00
}