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

Catch up main with updates from brokerpak-topic #7

Merged
merged 21 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3d97cdf
Rename AWS_ZONE to be more brokerpak-specific
jameshochadel Oct 8, 2024
4016e3b
Add a new field to test upgrading a service instance's plan
jameshochadel Oct 16, 2024
b42db3b
Test making the field required
jameshochadel Oct 16, 2024
6f045fc
Update brokerpak docs with better descriptions, formatting, and defaults
jameshochadel Oct 21, 2024
f7833cb
Ignore trivy finding that we cannot work around
jameshochadel Oct 28, 2024
61961bd
Change tags so the update service can find CSB services easily
jameshochadel Nov 13, 2024
e4eddd6
Add diagrams to support SCR
jameshochadel Nov 19, 2024
7839e4f
Minor diagram improvements
jameshochadel Nov 19, 2024
0196d6c
Parameterize docproxy broker URL and service port
jameshochadel Dec 10, 2024
94461ba
Add titles, SNS references, and other fixes to diagrams
jameshochadel Dec 10, 2024
7fce5bb
docproxy: Update title of docs page
jameshochadel Dec 10, 2024
f79d1d4
Drop test field
jameshochadel Dec 10, 2024
ce3af0e
Add make targets
jameshochadel Dec 10, 2024
8c5f64d
Add service-updater project and go.work to support
jameshochadel Dec 10, 2024
7fde7be
Serve cloud.gov logo from the application instead of our marketing site
jameshochadel Dec 10, 2024
a5627d1
Add Amazon SES image to offering & doc page
jameshochadel Dec 10, 2024
6084245
Fix pak build failure: image_url must be full URI, not path
jameshochadel Dec 10, 2024
f99bdc8
Drop reference to test field
jameshochadel Dec 10, 2024
c2d0293
Ignore local development database
jameshochadel Dec 10, 2024
a8ac84b
Rename brokerpak for consistency with other platform service offerings
jameshochadel Dec 10, 2024
9412e98
Drop unused field tag
jameshochadel Dec 10, 2024
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ clientconfig.yml
# Configuration for the CSB server.
secrets.env
zscaler.crt
# Sqlite database for local development.
.csb.db
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ RUN set -e; if [ "$BUILD_ENV" = "production" ] ; then echo "production env"; els
cp /app/zscaler.crt $CERT_DIR ; update-ca-certificates ; \
fi

RUN /app/csb pak build brokerpaks/cg-smtp
RUN /app/csb pak build brokerpaks/aws-ses

FROM ${base_image}

# Copy brokerpaks to final image
COPY --from=build /app/cg-smtp-0.1.0.brokerpak /app/
COPY --from=build /app/aws-ses-0.1.0.brokerpak /app/
11 changes: 9 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
build:
PAK_BUILD_CACHE_PATH=/tmp/pak-build-cache cloud-service-broker pak build brokerpaks/cg-smtp
PAK_BUILD_CACHE_PATH=/tmp/pak-build-cache cloud-service-broker pak build brokerpaks/aws-ses

run: build
# Load environment variables from secrets.env, scoped to this command only.
@bash -c 'env $$(cat secrets.env | xargs) cloud-service-broker serve'

watch:
find . | grep -E '\.env|\.tf' | entr -r make run
find . | grep -E '\.env|\.tf|\.yml' | entr -r make run

clean:
rm -r /tmp/pak-build-cache
rm *.brokerpak

run-docproxy:
find docproxy | entr -r go run ./docproxy/.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,7 @@ This repo contains configuration, including brokerpaks, for the cloud.gov deploy

- https://github.com/GSA-TTS/datagov-brokerpak-smtp
- https://github.com/GSA/ttsnotify-brokerpak-sms

## Credits

- AWS Architecture icons are sourced from https://aws.amazon.com/architecture/icons/.
44 changes: 21 additions & 23 deletions brokerpaks/cg-smtp/cg-smtp.yml → brokerpaks/aws-ses/aws-ses.yml
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
version: 1
name: cg-smtp
name: aws-ses
id: 260f2ead-b9e9-48b5-9a01-6e3097208ad7
description: SMTP service provided by Amazon Simple Email Service (SES)
display_name: SMTP (using AWS SES)
image_url: https://example.com/icon.jpg
description: Send email from verified domains using Amazon Simple Email Service (SES). Supports SMTP and the SES HTTP API.
display_name: AWS Simple Email Service
image_url: https://services.cloud.gov/images/amazon-ses.svg
documentation_url: https://aws.amazon.com/ses/ # todo
provider_display_name: ""
provider_display_name: "Cloud.gov"
support_url: https://cloud.gov/contact/
tags: [aws, ses, smtp]
tags: [aws, csb]
plans:
- name: base
id: 35ffb84b-a898-442e-b5f9-0a6a5229827d
description: Provision SMTP credentials for sending email from any user at a domain, like 'agency.gov'.
description: Provision SMTP credentials for sending email from any user at a domain, like `agency.gov`.
display_name: Send-only service
provision:
plan_inputs:
user_inputs:
- field_name: domain
type: string
default: ""
details: Domain from mail will be sent. For example, agency.gov. If left empty, a temporary cloud.gov subdomain will be generated.
required: false
prohibit_update: true
details: Domain from which mail will be sent. For example, `agency.gov`. If left empty, a temporary cloud.gov subdomain will be generated.
- field_name: dmarc_report_uri_aggregate
type: string
required: true
default: ""
details: The mailto URI to which DMARC aggregate reports should be sent. For example, 'mailto:[email protected]'. Reports are automatically sent to [email protected].
details: The mailto URI to which DMARC aggregate reports should be sent. For example, `mailto:[email protected]`. Reports are automatically sent to `[email protected]`. If you specify a domain and later update this parameter, remember to update your DNS with the new records in the `required_records` output.
- field_name: dmarc_report_uri_failure
type: string
required: true
default: ""
details: The mailto URI to which DMARC individual message failure reports should be sent. For example, 'mailto:[email protected]'.
details: The mailto URI to which DMARC individual message failure reports should be sent. For example, `mailto:[email protected]`. If you specify a domain and later update this parameter, remember to update your DNS with the new records in the `required_records` output.
- field_name: enable_feedback_notifications
type: boolean
details: Flag to toggle creation of SNS topics for feedback notifications.
default: false
- field_name: mail_from_subdomain
type: string
default: ""
details: Subdomain to use as the sending email server.
required: false
details: The custom MAIL FROM domain that you want the verified identity to use. See the [SES v2 API reference](https://docs.aws.amazon.com/ses/latest/APIReference-V2/API_PutEmailIdentityMailFromAttributes.html) for requirements.
computed_inputs:
- name: aws_access_key_id_govcloud
type: string
Expand All @@ -60,7 +59,7 @@ provision:
- name: default_domain
overwrite: true
type: string
default: ${config("aws.zone")}
default: ${config("cg_smtp.aws.zone")}
- name: labels
default: ${json.marshal(request.default_labels)}
overwrite: true
Expand All @@ -73,7 +72,7 @@ provision:
default: ${request.context}
- name: service_offering_name
type: string
default: cg-smtp
default: aws-ses
- name: service_plan_name
type: string
default: base
Expand All @@ -89,10 +88,10 @@ provision:
details: If a domain was supplied, you must create these records in that zone in your DNS system.
- field_name: dmarc_report_uri_aggregate
type: string
details: The mailto URI to which DMARC aggregate reports should be sent. For example, 'mailto:[email protected]'. Reports are automatically sent to [email protected].
details: The mailto URI to which DMARC aggregate reports should be sent. For example, `mailto:[email protected]`. Reports are automatically sent to `[email protected]`.
- field_name: dmarc_report_uri_failure
type: string
details: The mailto URI to which DMARC individual message failure reports should be sent. For example, 'mailto:[email protected]'.
details: The mailto URI to which DMARC individual message failure reports should be sent. For example, `mailto:[email protected]`.
- field_name: instructions
type: string
details: Any further steps that you must take before using the service.
Expand All @@ -101,7 +100,7 @@ provision:
details: ARN of the SES Configuration Set associated with the identity. Used to create bindings.
- field_name: domain_arn
type: string
details: Instance SES domain identity (used when creating bindings)
details: Instance SES domain identity. Used to create bindings.
- field_name: bounce_topic_arn
type: string
details: ARN of the SNS topic receiving bounce feedback notifications.
Expand All @@ -125,11 +124,10 @@ bind:
- field_name: source_ips
type: array
default: []
details: IP Ranges that requests to SES must come from.
details: A list of IP ranges in CIDR format. If specified, requests made with this binding must originate from the specified ranges. By default, all requests are allowed.
prohibit_update: false
- field_name: notification_webhook
type: string
default: ""
details: HTTPS endpoint to subscribe to feedback notifications.
computed_inputs:
- name: aws_access_key_id_govcloud
Expand Down Expand Up @@ -177,7 +175,7 @@ bind:
default: ${request.context}
- name: service_offering_name
type: string
default: cg-smtp
default: aws-ses
- name: service_plan_name
type: string
default: base
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
type VCAPServices struct {
SMTPService []struct {
Credentials Credentials `json:"credentials"`
} `json:"cg-smtp"`
} `json:"aws-ses"`
}

type Credentials struct {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
packversion: 1
name: cg-smtp
name: aws-ses
version: 0.1.0
metadata:
author: cloud.gov team
Expand All @@ -22,23 +22,23 @@ terraform_binaries:
version: 5.53.0
source: https://github.com/terraform-providers/terraform-provider-aws/archive/v5.53.0.zip
service_definitions:
- cg-smtp.yml
- aws-ses.yml
parameters: []
required_env_variables:
- AWS_ZONE
- AWS_ACCESS_KEY_ID_COMMERCIAL
- AWS_ACCESS_KEY_ID_GOVCLOUD
- AWS_SECRET_ACCESS_KEY_GOVCLOUD
- AWS_REGION_COMMERCIAL
- AWS_REGION_GOVCLOUD
- AWS_ACCESS_KEY_ID_COMMERCIAL
- AWS_SECRET_ACCESS_KEY_COMMERCIAL
- AWS_REGION_COMMERCIAL
- AWS_SECRET_ACCESS_KEY_GOVCLOUD
- CG_SMTP_AWS_ZONE
- CLOUD_GOV_ENVIRONMENT
env_config_mapping:
AWS_ACCESS_KEY_ID_COMMERCIAL: aws.commercial.access_key_id
AWS_ACCESS_KEY_ID_GOVCLOUD: aws.govcloud.access_key_id
AWS_SECRET_ACCESS_KEY_GOVCLOUD: aws.govcloud.secret_access_key
AWS_REGION_COMMERCIAL: aws.commercial.region
AWS_REGION_GOVCLOUD: aws.govcloud.region
AWS_ACCESS_KEY_ID_COMMERCIAL: aws.commercial.access_key_id
AWS_SECRET_ACCESS_KEY_COMMERCIAL: aws.commercial.secret_access_key
AWS_REGION_COMMERCIAL: aws.commercial.region
AWS_ZONE: aws.zone
AWS_SECRET_ACCESS_KEY_GOVCLOUD: aws.govcloud.secret_access_key
CG_SMTP_AWS_ZONE: cg_smtp.aws.zone
CLOUD_GOV_ENVIRONMENT: cloud_gov.environment
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ locals {
subscribed_webhook = ((local.subscribe_bounce_notification || local.subscribe_complaint_notification || local.subscribe_delivery_notification) ? var.notification_webhook : null)
}

# Trivy: It is best practice to manage access via groups intead of by directly attaching
# policies to users. However, each binding may specify separate source IP constraints
# on sending, so we cannot use a group with a single policy for all users.
#trivy:ignore:AVD-AWS-0143
resource "aws_iam_user" "user" {
name = local.user_name
path = "/cf/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ locals {
resource "aws_sesv2_email_identity" "identity" {
configuration_set_name = aws_sesv2_configuration_set.config.configuration_set_name
email_identity = local.domain
# Should match https://github.com/cloud-gov/go-broker-tags/blob/main/tags.go#L10

lifecycle {
prevent_destroy = true
Expand Down
2 changes: 1 addition & 1 deletion docproxy/go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/cloud-gov/csb-docproxy
module github.com/cloud-gov/csb/docproxy

go 1.23.1

Expand Down
10 changes: 10 additions & 0 deletions docproxy/images/amazon-ses.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docproxy/images/cloud-gov-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 72 additions & 6 deletions docproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ package main

import (
"embed"
"fmt"
"log/slog"
"net/http"
"net/url"
"os"
"slices"
"strconv"
"strings"

"golang.org/x/net/html"
Expand Down Expand Up @@ -85,6 +89,19 @@ func modifyDocument(n *html.Node) {

return false
},
func(n *html.Node) bool {
if n.Type == html.TextNode && n.Parent.Parent.Type == html.ElementNode && n.Parent.Data == "a" {
cls := html.Attribute{
Key: "class",
Val: "navbar-brand",
}
if i := slices.Index(n.Parent.Attr, cls); i >= 0 {
// Change page title.
n.Data = "Services Reference"
}
}
return false
},
}
walk(n, func(n *html.Node) bool {
for _, m := range modifications {
Expand All @@ -106,10 +123,13 @@ var fonts embed.FS
//go:embed images/favicon.ico
var favicon []byte

// run registers routes and starts the server. It is separate from main so it
// can return errors conventionally and main can handle them all in one place.
func run() error {
slog.SetLogLoggerLevel(slog.LevelInfo)
//go:embed images/cloud-gov-logo.svg
var logo []byte

//go:embed images/amazon-ses.svg
var amazonSES []byte

func routes(c config) {
http.HandleFunc("/styles.css", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "text/css; charset=utf-8")
w.Write(stylesheet)
Expand All @@ -127,8 +147,16 @@ func run() error {
w.Header().Add("Content-Type", "image/vnd.microsoft.icon")
w.Write(favicon)
})
http.HandleFunc("/images/cloud-gov-logo.svg", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "image/svg+xml")
w.Write(logo)
})
http.HandleFunc("/images/amazon-ses.svg", func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "image/svg+xml")
w.Write(amazonSES)
})
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
resp, err := http.Get("https://csb.dev.us-gov-west-1.aws-us-gov.cloud.gov")
resp, err := http.Get(c.BrokerURL.String())
if err != nil {
slog.Error("Getting CSB site", "error", err)
w.WriteHeader(http.StatusBadGateway)
Expand All @@ -148,8 +176,46 @@ func run() error {
w.WriteHeader(http.StatusInternalServerError)
}
})
}

type config struct {
Port uint16
BrokerURL *url.URL
}

func loadConfig() (config, error) {
c := config{}

port := os.Getenv("PORT")
p, err := strconv.ParseUint(port, 10, 16)
if err != nil {
return config{}, fmt.Errorf("Invalid PORT: %w", err)
}
c.Port = uint16(p)

brokerURL := os.Getenv("BROKER_URL")
u, err := url.Parse(brokerURL)
if err != nil {
return config{}, fmt.Errorf("Invalid BROKER_URL: %w", err)
}
c.BrokerURL = u

return c, nil
}

// run registers routes and starts the server. It is separate from main so it
// can return errors conventionally and main can handle them all in one place.
func run() error {
slog.SetLogLoggerLevel(slog.LevelInfo)
config, err := loadConfig()
if err != nil {
return err
}

routes(config)
addr := fmt.Sprintf("localhost:%v", config.Port)
slog.Info("Starting server...")
return http.ListenAndServe("localhost:8080", nil)
return http.ListenAndServe(addr, nil)
}

func main() {
Expand Down
Loading