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 S3 and Cloudfront Subchecks #131

Merged
merged 8 commits into from
Jan 3, 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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.16
go-version: 1.19

- name: Test
run: go test -v ./...
Expand Down
126 changes: 114 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# check_cloud_aws

Icinga check plugin to check Amazon AWS resources. At the moment the check only supports EC2 instances.
Icinga check plugin to check Amazon AWS resources. At the moment the check supports EC2 instances, Cloudfront and S3
Buckets.

## Usage

Expand All @@ -22,10 +23,10 @@ Flags:
-n, --name string Search for ec2 instances by name (e.g. instance*)

Global Flags:
-P, --profile string AWS credential profile (~/.aws/credentials)
-R, --region string AWS region name (e.g. eu-central-1)
-t, --timeout int Timeout for the check (default 30)

-C, --credentials-file string Path to the credentials file (default "~/.aws/credentials")
-P, --profile string The AWS profile name, which represents a separate credential profile in the credential file (default "default")
-R, --region string The AWS region to send requests to (default "eu-central-1")
-t, --timeout int Timeout for the check (default 30)
```

```
Expand All @@ -52,9 +53,10 @@ Flags:
-n, --name string Look for ec2 instance by name

Global Flags:
-P, --profile string AWS credential profile (~/.aws/credentials)
-R, --region string AWS region name (e.g. eu-central-1)
-t, --timeout int Timeout for the check (default 30)
-C, --credentials-file string Path to the credentials file (default "~/.aws/credentials")
-P, --profile string The AWS profile name, which represents a separate credential profile in the credential file (default "default")
-R, --region string The AWS region to send requests to (default "eu-central-1")
-t, --timeout int Timeout for the check (default 30)
```

```
Expand All @@ -66,14 +68,115 @@ Type: t2.micro
AutoScaling: (none)
```

### S3

In the bucket context, calculates the size of the bucket and alerts if its size reaches the threshold.
In the object context, the size of each object inside a bucket will be checked against the threshold.

#### s3 bucket

````
Usage:
check_cloud_aws s3 bucket [flags]

Flags:
-b, --buckets strings Name of the S3 bucket. If '--buckets' is empty, all buckets will be evaluated.
-c, --crit-bucket-size string Critical threshold for the size of the specified bucket. Alerts if size is greater than critical threshold.
Possible values are MB, GB or TB. Without any identifier specified MB is used. (default "20Gb")
-w, --warn-bucket-size string Warning threshold for the size of the specified bucket. Alerts if size is greater than warning threshold.
Possible values are MB, GB or TB. Without any identifier specified MB is used. (default "10Gb")
-h, --help help for bucket

Global Flags:
-C, --credentials-file string Path to the credentials file (default "~/.aws/credentials")
-P, --profile string The AWS profile name, which represents a separate credential profile in the credential file (default "default")
-R, --region string The AWS region to send requests to (default "eu-central-1")
-t, --timeout int Timeout for the check (default 30)
````

```
$ check_cloud_aws s3 bucket -w 100mb -c 200mb
OK - Found 2 buckets - critical 0 - warning 0
[OK] my-aws-test-bucket1: 50MiB
[OK] my-aws-test-bucket2: 60MiB | my-aws-test-bucket1=50MB;100;200 my-aws-test-bucket2=60MB;100;200
```

### s3 object

````
Usage:
check_cloud_aws s3 object [flags]

Flags:
-b, --buckets strings Name of one or multiple S3 buckets. If '--buckets' is empty, all buckets will be evaluated.
--prefix string Limits the response to keys that begin with the specified prefix, e.G. '--prefix test' filters all objects which starts with 'test'.
NOTE: Keep in mind, that objects beneath a directory will be ignored!
-c, --crit-object-size string Critical threshold for the size of the object. Alerts if size is greater than critical threshold.
Possible values are MB, GB or TB. Without any identifier specified MB is used. (default "1gb")
-w, --warn-object-size string Critical threshold for the size of the object. Alerts if size is greater than warning threshold.
Possible values are MB, GB or TB. Without any identifier specified MB is used. (default "800mb")
-p, --perfdata Displays perfdata and lists ALL objects in the specified bucket.
-h, --help help for object

Global Flags:
-C, --credentials-file string Path to the credentials file (default "~/.aws/credentials")
-P, --profile string The AWS profile name, which represents a separate credential profile in the credential file (default "default")
-R, --region string The AWS region to send requests to (default "eu-central-1")
-t, --timeout int Timeout for the check (default 30)
````

````
$ check_cloud_aws s3 object --perfdata --prefix 'test' -b 'my-aws-testbucket1'
OK - Found 3 objects - critical 0 - warning 0 | test-file2.jpg=20MB;800;1024 test-file3.gif=10MB;800;1024 test-file5.rtf=10MB;800;1024

````

### Cloudfront

Checks a specific or multiple cloudfront distributions from a region. When the state is `disabled` or `InProgress`,
the check will alert.

````
Usage:
check_cloud_aws cloudfront [flags]

Flags:
-e, --etag strings Etag name of one or multiple distributions. If '--etag' is empty, all distributions will be evaluated.
-h, --help help for cloudfront

Global Flags:
-C, --credentials-file string Path to the credentials file (default "~/.aws/credentials")
-P, --profile string The AWS profile name, which represents a separate credential profile in the credential file (default "default")
-R, --region string The AWS region to send requests to (default "eu-central-1")
-t, --timeout int Timeout for the check (default 30)
````

````
$ check_cloud_aws cloudfront
CRITICAL - Found 2 Distributions - critical 1 - warning 1

[WARNING] E32127W2BLH4SR status=InProgress enabled=true
[CRITICAL] E16D3ZI1743SVJ status=Deployed enabled=false
| E32127W2BLH4SR=InProgress E16D3ZI1743SVJ=Deployed
````

## Authentication

Create a new IAM account for API access, add the required **read-only permissions, and check can monitor resources on
that account.

Permissions:
Permission EC2:

* `arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess`

Permission Cloudfront:

* `arn:aws:iam::aws:policy/CloudFrontReadOnlyAccess`

Permission S3:

* `arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess`

You can use the common AWS environment variables for the check, but we recommend storing the credentials in
the standard AWS locations on disk.

Expand All @@ -100,7 +203,6 @@ The region setting here influences the default region of check_cloud_aws, which
region = eu-central-1
```


## Further Documentation

* [AWS SDK for Go](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html)
Expand All @@ -117,8 +219,8 @@ the Free Software Foundation, either version 3 of the License, or

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
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see [gnu.org/licenses](https://www.gnu.org/licenses/).
along with this program. If not, see [gnu.org/licenses](https://www.gnu.org/licenses/).
122 changes: 122 additions & 0 deletions cmd/cloudfront.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package cmd

import (
"fmt"
"github.com/NETWAYS/check_cloud_aws/internal/cloudfront"
"github.com/NETWAYS/check_cloud_aws/internal/common"
"github.com/NETWAYS/go-check"
"github.com/NETWAYS/go-check/perfdata"
"github.com/NETWAYS/go-check/result"
c "github.com/aws/aws-sdk-go/service/cloudfront"
"github.com/spf13/cobra"
)

var (
ETags []string
)

var cloudfrontCmd = &cobra.Command{
Use: "cloudfront",
Short: "Checks in the Cloudfront context",
Run: func(cmd *cobra.Command, args []string) {
var (
output string
summary string
totalCrit int
totalWarn int
rc int
states []int
distributions []*c.GetDistributionOutput
perf perfdata.PerfdataList
)

client := RequireCloudfrontClient()

if ETags == nil {
distributionsList, err := client.LoadAllDistributions()
if err != nil {
check.ExitError(err)
}

for _, dist := range distributionsList.DistributionList.Items {
distribution, err := client.LoadDistributionByETag(*dist.Id)
if err != nil {
check.ExitError(err)
}

distributions = append(distributions, distribution)
}
} else {
for _, etag := range ETags {
distribution, err := client.LoadDistributionByETag(etag)
if err != nil {
check.ExitError(err)
}

distributions = append(distributions, distribution)
}
}

summary += fmt.Sprintf("Found %d Distributions - ", len(distributions))

for _, distribution := range distributions {
if *distribution.Distribution.DistributionConfig.Enabled == false {
rc = 2
totalCrit++
} else if *distribution.Distribution.Status == "InProgress" {
rc = 1
totalWarn++
} else {
rc = 0
}

states = append(states, rc)

if rc != 0 {
output += client.GetOutput(rc, distribution)
}

p := perfdata.Perfdata{
Label: *distribution.Distribution.Id,
Value: *distribution.Distribution.Status,
}

perf.Add(&p)

if len(distributions) > 1 {
output += "\n"
}
}

if result.WorstState(states...) == 0 {
output = fmt.Sprintf("")
}

summary += fmt.Sprintf("critical %d - warning %d\n", totalCrit, totalWarn)

if len(distributions) > 1 {
if result.WorstState(states...) != 0 {
summary += "\n"
}
}

check.ExitRaw(result.WorstState(states...), summary+output, "|", perf.String())
},
}

func init() {
cloudfrontFlags := cloudfrontCmd.Flags()
cloudfrontFlags.StringSliceVarP(&ETags, "etag", "e", nil,
"Etag name of one or multiple distributions. If '--etag' is empty, all distributions will be evaluated.")

cloudfrontFlags.SortFlags = false
}

func RequireCloudfrontClient() *cloudfront.CloudfrontClient {
session, err := common.CreateSession(CredentialsFile, Profile, Region)
if err != nil {
check.ExitError(fmt.Errorf("could not setup AWS API session: %w", err))
}

return cloudfront.NewCloudfrontClient(session)
}
2 changes: 1 addition & 1 deletion cmd/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var ec2Cmd = &cobra.Command{
}

func RequireEC2Client() *ec2.Client {
session, err := common.CreateSession(Profile, Region)
session, err := common.CreateSession(CredentialsFile, Profile, Region)
if err != nil {
check.ExitError(fmt.Errorf("could not setup AWS API session: %w", err))
}
Expand Down
25 changes: 19 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
)

var (
Timeout = 30
Profile string
Region string
Timeout = 30
Profile string
Region string
CredentialsFile string
)

var rootCmd = &cobra.Command{
Expand Down Expand Up @@ -39,10 +40,22 @@ func Help(cmd *cobra.Command, strings []string) {

func init() {
rootCmd.AddCommand(ec2Cmd)
rootCmd.SetHelpFunc(Help)
rootCmd.AddCommand(s3Cmd)
rootCmd.AddCommand(cloudfrontCmd)

rootCmd.CompletionOptions.DisableDefaultCmd = true
rootCmd.DisableAutoGenTag = true
rootCmd.SetHelpCommand(&cobra.Command{
Use: "no-help",
Hidden: true,
})

p := rootCmd.PersistentFlags()
p.StringVarP(&CredentialsFile, "credentials-file", "C", "~/.aws/credentials", "Path to the credentials file")
p.StringVarP(&Region, "region", "R", "eu-central-1", "The AWS region to send requests to")
p.StringVarP(&Profile, "profile", "P", "default", "The AWS profile name, which represents a separate credential profile in the credential file")
p.IntVarP(&Timeout, "timeout", "t", Timeout, "Timeout for the check")
p.StringVarP(&Profile, "profile", "P", Profile, "AWS credential profile (~/.aws/credentials)")
p.StringVarP(&Region, "region", "R", Region, "AWS region name (e.g. eu-central-1)")

rootCmd.Flags().SortFlags = false
p.SortFlags = false
}
27 changes: 27 additions & 0 deletions cmd/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cmd

import (
"fmt"
"github.com/NETWAYS/check_cloud_aws/internal/common"
"github.com/NETWAYS/check_cloud_aws/internal/s3"
"github.com/NETWAYS/go-check"

"github.com/spf13/cobra"
)

var BucketNames []string

var s3Cmd = &cobra.Command{
Use: "s3",
Short: "Checks in the S3 context",
Run: Help,
}

func RequireS3Client() *s3.S3Client {
session, err := common.CreateSession(CredentialsFile, Profile, Region)
if err != nil {
check.ExitError(fmt.Errorf("could not setup AWS API session: %w", err))
}

return s3.NewS3Client(session)
}
Loading