Files
teleport/lib/cloud/aws/errors.go
T
rosstimothy b7318b5c7e Enable errorlint via golangci-lint (#37669)
Adds the new linter and configures it to prevent direct error
comparisions and type assertions in favor of errors.Is and errors.As.
All current violations caught by the linter have been updated
accordingly.
2024-02-02 15:59:24 +00:00

140 lines
4.3 KiB
Go

/*
* Teleport
* Copyright (C) 2023 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package aws
import (
"errors"
"net/http"
"strings"
awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
"github.com/aws/aws-sdk-go-v2/config"
iamTypes "github.com/aws/aws-sdk-go-v2/service/iam/types"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/iam"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
"github.com/gravitational/trace"
)
// ConvertRequestFailureError converts `error` into AWS RequestFailure errors
// to trace errors. If the provided error is not an `RequestFailure` it returns
// the error without modifying it.
func ConvertRequestFailureError(err error) error {
var requestErr awserr.RequestFailure
if !errors.As(err, &requestErr) {
return err
}
return convertRequestFailureErrorFromStatusCode(requestErr.StatusCode(), requestErr)
}
func convertRequestFailureErrorFromStatusCode(statusCode int, requestErr error) error {
switch statusCode {
case http.StatusForbidden:
return trace.AccessDenied(requestErr.Error())
case http.StatusConflict:
return trace.AlreadyExists(requestErr.Error())
case http.StatusNotFound:
return trace.NotFound(requestErr.Error())
case http.StatusBadRequest:
// Some services like memorydb, redshiftserverless may return 400 with
// "AccessDeniedException" instead of 403.
if strings.Contains(requestErr.Error(), redshiftserverless.ErrCodeAccessDeniedException) {
return trace.AccessDenied(requestErr.Error())
}
}
return requestErr // Return unmodified.
}
// ConvertIAMError converts common errors from IAM clients to trace errors.
func ConvertIAMError(err error) error {
// By error code.
var awsErr awserr.Error
if errors.As(err, &awsErr) {
switch awsErr.Code() {
case iam.ErrCodeUnmodifiableEntityException:
return trace.AccessDenied(awsErr.Error())
case iam.ErrCodeNoSuchEntityException:
return trace.NotFound(awsErr.Error())
case iam.ErrCodeMalformedPolicyDocumentException,
iam.ErrCodeInvalidInputException,
iam.ErrCodeDeleteConflictException:
return trace.BadParameter(awsErr.Error())
case iam.ErrCodeLimitExceededException:
return trace.LimitExceeded(awsErr.Error())
}
}
// By status code.
return ConvertRequestFailureError(err)
}
// parseMetadataClientError converts a failed instance metadata service call to a trace error.
func parseMetadataClientError(err error) error {
var httpError interface{ HTTPStatusCode() int }
if errors.As(err, &httpError) {
return trace.ReadError(httpError.HTTPStatusCode(), nil)
}
return trace.Wrap(err)
}
// ConvertIAMv2Error converts common errors from IAM clients to trace errors.
func ConvertIAMv2Error(err error) error {
if err == nil {
return nil
}
var entityExistsError *iamTypes.EntityAlreadyExistsException
if errors.As(err, &entityExistsError) {
return trace.AlreadyExists(*entityExistsError.Message)
}
var entityNotFound *iamTypes.NoSuchEntityException
if errors.As(err, &entityNotFound) {
return trace.NotFound(*entityNotFound.Message)
}
var malformedPolicyDocument *iamTypes.MalformedPolicyDocumentException
if errors.As(err, &malformedPolicyDocument) {
return trace.BadParameter(*malformedPolicyDocument.Message)
}
var re *awshttp.ResponseError
if errors.As(err, &re) {
return convertRequestFailureErrorFromStatusCode(re.HTTPStatusCode(), re.Err)
}
return err
}
// ConvertLoadConfigError converts common AWS config loading errors to trace errors.
func ConvertLoadConfigError(configErr error) error {
var sharedConfigProfileNotExistError config.SharedConfigProfileNotExistError
switch {
case errors.As(configErr, &sharedConfigProfileNotExistError):
return trace.NotFound(configErr.Error())
}
return configErr
}