Skip to main content

AWS S3 Configuration

Overview

This guide provides comprehensive instructions for configuring AWS S3 as your object storage backend for the Appcircle server. While the default Helm chart deployment includes MinIO as an in-cluster object storage solution, production environments benefit from using a more robust and scalable solution like AWS S3.

caution

You need to use version 0.4.0 or higher of the Appcircle server Helm chart before applying this configuration. Please check the Appcircle server version and update the Helm chart if necessary.

What This Guide Covers

This guide will walk you through the process of configuring AWS S3 as your object storage backend for the Appcircle server. To use AWS S3 with Appcircle server, you need to:

  • Set up AWS infrastructure: S3 buckets, IAM users, and permissions
  • Configure Appcircle server: Update Helm values to use S3
  • Optional CDN setup: CloudFront for performance optimization
caution

If your Appcircle server is installed and contains data, changing or migrating to a different object storage provider is not supported. Object storage configuration must be finalized during the initial installation process.

Prerequisites

To complete this guide, you must have the following:

1. AWS Account and Permissions

An AWS account with appropriate permissions to create and manage S3 buckets, IAM users, and policies.

Click to view more details about AWS permissions.

You need the following AWS permissions to complete this configuration:

  • S3 permissions: Create buckets, configure CORS, manage bucket policies
  • IAM permissions: Create users, policies, and access keys
  • STS permissions: Get caller identity (for policy attachment)
  • CloudFront permissions: Create distributions, manage origins, and configure caching

If you're working in a restricted environment, ensure you have the necessary permissions before proceeding.

2. AWS CLI

The AWS CLI version 2.x is required and must be installed and configured on your machine.

Click to view more details about AWS CLI configuration.

To configure AWS CLI, you need:

  • Access Key ID and Secret Access Key for your AWS account
  • Default region for your AWS resources
  • Output format (JSON is recommended)

You can configure AWS CLI using:

aws configure

Or by setting environment variables:

export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
export AWS_DEFAULT_OUTPUT=json
warning

Please make sure that the output format is set to json to avoid any issues with the jq command in the next steps.

3. Kubernetes/OpenShift Access

kubectl (for Kubernetes) or oc (for OpenShift) CLI is required and must be configured to access your cluster.

info

This guide assumes you have administrative access to your AWS account and Kubernetes/OpenShift cluster. If you're working in a restricted environment, ensure you have the necessary permissions before proceeding.

4. Basic Understanding

Basic understanding of AWS IAM, S3, and Kubernetes/OpenShift concepts is recommended.

5. Optional: Domain and SSL Certificates

For CloudFront CDN setup (optional), you'll need:

  • Domain name: For custom CDN domains
  • SSL certificates: For HTTPS access to your CDN

Configuration Steps

1. Set Up Environment Variables

Set up your environment variables before proceeding with the configuration. These variables will be used throughout the configuration process.

note

In this documentation, we will use spacetech as an example organization name and us-east-1 as an example AWS region. You should replace these values with your actual organization name and preferred AWS region.

# Set your organization name and region
ORG_NAME="spacetech" # Replace with your organization name
BUCKET_PREFIX="appcircle-${ORG_NAME}-"
REGION="us-east-1" # Replace with your preferred AWS region
IAM_USER="appcircle-server"

2. Create AWS S3 Buckets

Create the required S3 buckets to store the artifacts generated by the Appcircle server.

Appcircle server requires the following S3 buckets for different purposes:

  • ${BUCKET_PREFIX}temp: Temporary files and uploads (requires CORS configuration for direct uploads/downloads from the client browsers)
  • ${BUCKET_PREFIX}build: Build artifacts and logs
  • ${BUCKET_PREFIX}distribution: Testing Distribution files
  • ${BUCKET_PREFIX}storesubmit: Appcircle Store Submit files
  • ${BUCKET_PREFIX}store: Enterprise App Store files
  • ${BUCKET_PREFIX}agent-cache: Appcircle Runner cache files
  • ${BUCKET_PREFIX}backup: Backup files
  • ${BUCKET_PREFIX}publish: Published mobile app binaries
tip

Bucket Naming: Bucket names must be globally unique across all AWS accounts. Using your organization name as a prefix ensures uniqueness.

Create all required buckets:

# Create buckets one by one
aws s3 mb s3://${BUCKET_PREFIX}temp --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}build --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}distribution --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}storesubmit --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}store --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}agent-cache --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}backup --region ${REGION}
aws s3 mb s3://${BUCKET_PREFIX}publish --region ${REGION}
info

The bucket names use your organization name to ensure global uniqueness, as AWS S3 bucket names must be unique across all AWS accounts worldwide.

3. Configure CORS Settings

Configure CORS settings for the temp bucket to allow cross-origin requests from your Appcircle server dashboard.

caution

Replace the https://my.appcircle.spacetech.com with the dashboard URL that you will use to access the Appcircle server. For example, if you are using .appcircle.spacetech.com as the domain in the Helm values.yaml file, the dashboard URL will be https://my.appcircle.spacetech.com.

Configure CORS for the temp bucket:

aws s3api put-bucket-cors \
--bucket ${BUCKET_PREFIX}temp \
--region ${REGION} \
--cors-configuration '{
"CORSRules": [
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedOrigins": ["https://my.appcircle.spacetech.com"],
"ExposeHeaders": [],
"MaxAgeSeconds": 3600
}
]
}'
tip
  • The CORS configuration is only required for the temp bucket.
  • Other buckets don't require CORS configuration, as they are accessed server-side.
  • If you're using the Appcircle server dashboard with HTTP instead of HTTPS, replace https:// with http:// in the AllowedOrigins.

4. Create IAM User and Policy

Create an IAM user with minimal permissions to make the Appcircle server able to access the S3 buckets.

aws iam create-user --user-name ${IAM_USER}

Create an IAM policy that grants the necessary S3 permissions:

cat << EOF > appcircle-s3-policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::${BUCKET_PREFIX}temp",
"arn:aws:s3:::${BUCKET_PREFIX}temp/*",
"arn:aws:s3:::${BUCKET_PREFIX}build",
"arn:aws:s3:::${BUCKET_PREFIX}build/*",
"arn:aws:s3:::${BUCKET_PREFIX}distribution",
"arn:aws:s3:::${BUCKET_PREFIX}distribution/*",
"arn:aws:s3:::${BUCKET_PREFIX}storesubmit",
"arn:aws:s3:::${BUCKET_PREFIX}storesubmit/*",
"arn:aws:s3:::${BUCKET_PREFIX}store",
"arn:aws:s3:::${BUCKET_PREFIX}store/*",
"arn:aws:s3:::${BUCKET_PREFIX}agent-cache",
"arn:aws:s3:::${BUCKET_PREFIX}agent-cache/*",
"arn:aws:s3:::${BUCKET_PREFIX}backup",
"arn:aws:s3:::${BUCKET_PREFIX}backup/*",
"arn:aws:s3:::${BUCKET_PREFIX}publish",
"arn:aws:s3:::${BUCKET_PREFIX}publish/*"
]
}
]
}
EOF

Create the IAM policy:

aws iam create-policy \
--policy-name ${IAM_USER}-s3-policy \
--policy-document file://appcircle-s3-policy.json

Get your AWS account ID:

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

Attach the policy to the IAM user:

aws iam attach-user-policy \
--user-name ${IAM_USER} \
--policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/${IAM_USER}-s3-policy

5. Create Access Keys for the IAM User

Create access keys for the IAM user to be used by Appcircle server:

ACCESS_KEY_OUTPUT=$(aws iam create-access-key --user-name ${IAM_USER})
ACCESS_KEY_ID=$(echo "$ACCESS_KEY_OUTPUT" | jq -r '.AccessKey.AccessKeyId')
SECRET_ACCESS_KEY=$(echo "$ACCESS_KEY_OUTPUT" | jq -r '.AccessKey.SecretAccessKey')
warning

CRITICAL: Save the access key and secret access key securely. You'll need these credentials in the next step to create the Kubernetes secret.

6. Validate Basic S3 Configuration

Before proceeding to CloudFront setup (optional) or Kubernetes secret creation, verify your basic S3 configuration:

# 1. Verify all buckets were created successfully
echo "Checking S3 buckets..."
aws s3 ls | grep ${BUCKET_PREFIX}

# 2. Verify CORS configuration on temp bucket
echo "Checking CORS configuration..."
aws s3api get-bucket-cors --bucket ${BUCKET_PREFIX}temp

# 3. Verify IAM user exists
echo "Checking IAM user..."
aws iam get-user --user-name ${IAM_USER}

# 4. Verify IAM policy is attached
echo "Checking IAM policy attachment..."
aws iam list-attached-user-policies --user-name ${IAM_USER}

Expected Output:

  • All 8 buckets should be listed
  • CORS configuration should show your Appcircle server URL
  • IAM user should exist and have the policy attached

7. Optional: Create CloudFront CDN for AWS S3 Buckets

CloudFront is AWS's Content Delivery Network (CDN) service that improves performance by caching your S3 content at edge locations worldwide. This reduces latency and improves download speeds for your users.

tip
  • Follow this guide if you need production-grade performance to serve your users globally.
  • Skip this section if you're setting up for development/testing or have a small or medium team.
    • You can always enable CloudFront later without reinstalling the Appcircle server.

This guide will walk you through the process of creating a CloudFront distribution for your S3 buckets with the aws CLI.

info

Flexibility Note: You can achieve the same results with other tools (AWS Console, Terraform, CloudFormation, etc.) as long as you create the same infrastructure components described in this documentation. You can also add additional configurations (security policies, monitoring, etc.) as long as you don't break the core requirements:

  • CloudFront must be configured to serve the S3 buckets
  • S3 bucket policies must be updated to allow CloudFront access
  • CloudFront public-private key pair must be created and configured
  • SSL certificate should be managed or imported for the CloudFront distribution
  • DNS must be configured to point to the CloudFront distribution
  • Kubernetes secret must contain the correct credentials for the CloudFront public-private key pair
  • Helm values must include the specified CDN configuration for the Appcircle server

Step 7.1: Generate Public and Private Keys for URL Signing

CloudFront uses signed URLs to secure access to your content. You need to generate a key pair for this.

# Generate a private key
openssl genrsa -out private_key.pem 2048

# Generate the public key
openssl rsa -in private_key.pem -pubout -out public_key.pem

# Convert the public key to single-line format (required by AWS)
SINGLE_LINE_PUBLIC_KEY=$(awk '{printf "%s\\n", $0}' public_key.pem)
caution

Security Note: Keep your private_key.pem file secure. Anyone with this key can create valid signed URLs for your content.

Step 7.2: Create CloudFront Public Key

Create a public key in CloudFront that will be used to verify signed URLs.

# Create the public key configuration
cat << EOF > public-key-config.json
{
"CallerReference": "appcircle-cdn-sign-key",
"Name": "appcircle-cdn-sign-key",
"EncodedKey": "${SINGLE_LINE_PUBLIC_KEY}",
"Comment": "appcircle cdn sign key"
}
EOF

# Create the public key in CloudFront
PUBLIC_KEY_ID=$(aws cloudfront create-public-key --public-key-config file://public-key-config.json --query 'PublicKey.Id' --output text)

Step 7.3: Create CloudFront Key Group

A key group allows you to manage multiple public keys together.

# Create key group configuration
cat << EOF > key-group.json
{
"Name": "appcircle-cdn-key-group",
"Items": ["${PUBLIC_KEY_ID}"]
}
EOF

# Create the key group
KEY_GROUP_ID=$(aws cloudfront create-key-group --key-group-config file://key-group.json --query 'KeyGroup.Id' --output text)

Save the Key Group ID from the output.

Step 7.4: Store Private Key in Kubernetes

The private key needs to be available to your Appcircle server for creating signed URLs.

# Convert private key to single line
SINGLE_LINE_PRIVATE_KEY=$(cat private_key.pem | tr -d '\n')

# Create Kubernetes secret with the private key
kubectl create secret generic appcircle-cdn-url-sign-key -n appcircle \
--from-literal="cdn-url-sign-key-name=${PUBLIC_KEY_ID}" \
--from-literal="cdn-url-sign-key=${SINGLE_LINE_PRIVATE_KEY}"

Step 7.5: Import SSL Certificate

If you want to use custom domains (like cdn.yourcompany.com), you need an SSL certificate.

caution

CloudFront requires SSL certificates to be in the us-east-1 region, regardless of where your S3 buckets are located.

Also make sure to change the fullchain.pem and privkey.pem to your actual certificate and private key file paths in the command below.

# Import your SSL certificate to us-east-1 region
CERTIFICATE_ARN=$(
aws acm import-certificate \
--certificate fileb://cert1.pem \
--certificate-chain fileb://fullchain1.pem \
--private-key fileb://privkey1.pem \
--region us-east-1 \
--query 'CertificateArn' \
--output text
)

Step 7.6: Create Origin Access Control

Origin Access Control (OAC) secures the connection between CloudFront and your S3 buckets.

# Create OAC configuration
cat << EOF > appcircle-oac-config.json
{
"Name": "Appcircle-S3-OAC",
"Description": "OAC for Appcircle S3 buckets",
"SigningBehavior": "always",
"SigningProtocol": "sigv4",
"OriginAccessControlOriginType": "s3"
}
EOF

# Create the origin access control
OAC_ID=$(aws cloudfront create-origin-access-control \
--origin-access-control-config file://appcircle-oac-config.json \
--query 'OriginAccessControl.Id' --output text)

Step 7.7: Create CloudFront Distribution

This is the main CloudFront distribution that will serve your S3 content.

Bucket List for CloudFront Setup:

  • ${BUCKET_PREFIX}distribution - Testing Distribution files
  • ${BUCKET_PREFIX}store - Enterprise App Store files
  • ${BUCKET_PREFIX}build - Build artifacts and logs
  • ${BUCKET_PREFIX}storesubmit - Appcircle Store Submit files
  • ${BUCKET_PREFIX}publish - Published mobile app binaries

For each bucket you want to serve via CloudFront, follow these steps:

  1. Set the bucket variable:
# Choose one of these buckets:
BUCKET=${BUCKET_PREFIX}distribution # For distribution files
# BUCKET=${BUCKET_PREFIX}store # For store files
# BUCKET=${BUCKET_PREFIX}build # For build artifacts
# BUCKET=${BUCKET_PREFIX}storesubmit # For store submit files
# BUCKET=${BUCKET_PREFIX}publish # For published binaries
  1. Create CloudFront distribution configuration for the selected bucket:
caution

Replace appcircle-cdn-domain.spacetech.com with your actual CDN domain for each bucket.

For example:

  • If you want to create a CDN for the distribution bucket, you can replace appcircle-cdn-domain.spacetech.com with appcircle-distribution-cdn.spacetech.com.
  • If you want to create a CDN for the store bucket, you can replace appcircle-cdn-domain.spacetech.com with appcircle-store-cdn.spacetech.com.
# Create CloudFront distribution configuration
cat << EOF > cloudfront-config-${BUCKET#${BUCKET_PREFIX}}.json
{
"CallerReference": "appcircle-${BUCKET#${BUCKET_PREFIX}}-bucket-cdn",
"Comment": "Appcircle ${BUCKET#${BUCKET_PREFIX}} Bucket CDN",
"Aliases": {
"Quantity": 1,
"Items": [
"appcircle-cdn-domain.spacetech.com"
]
},
"ViewerCertificate": {
"ACMCertificateArn": "${CERTIFICATE_ARN}",
"SSLSupportMethod": "sni-only",
"MinimumProtocolVersion": "TLSv1.2_2021",
"CertificateSource": "acm"
},
"Enabled": true,
"Origins": {
"Items": [
{
"Id": "S3Origin",
"DomainName": "${BUCKET}.s3.${REGION}.amazonaws.com",
"OriginAccessControlId": "${OAC_ID}",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
}
],
"Quantity": 1
},
"DefaultCacheBehavior": {
"TargetOriginId": "S3Origin",
"ViewerProtocolPolicy": "redirect-to-https",
"TrustedKeyGroups": {
"Enabled": true,
"Quantity": 1,
"Items": [
"${KEY_GROUP_ID}"
]
},
"AllowedMethods": {
"Quantity": 2,
"Items": [
"GET",
"HEAD"
],
"CachedMethods": {
"Quantity": 2,
"Items": [
"GET",
"HEAD"
]
}
},
"ForwardedValues": {
"QueryString": false,
"Cookies": {
"Forward": "none"
}
},
"MinTTL": 0,
"DefaultTTL": 86400,
"MaxTTL": 31536000
}
}
EOF
  1. Create the CloudFront distribution:
# Create the CloudFront distribution
aws cloudfront create-distribution --distribution-config file://cloudfront-config-${BUCKET#${BUCKET_PREFIX}}.json
  1. Save the CloudFront Distribution ARN and Distribution Domain Names from the output.

  2. Repeat for other buckets by changing the BUCKET variable and running steps 2-4 again.

tip

Save all Distribution ARNs: You'll need each CloudFront Distribution ARN for the bucket policy updates in the next step.

Step 7.8: Update S3 Bucket Policy

Allow CloudFront to access your S3 buckets securely.

For each bucket that has a CloudFront distribution, update the bucket policy:

  1. Set the bucket variable:
# Choose the bucket you want to update:
BUCKET=${BUCKET_PREFIX}distribution # For distribution files
# BUCKET=${BUCKET_PREFIX}store # For store files
# BUCKET=${BUCKET_PREFIX}build # For build artifacts
# BUCKET=${BUCKET_PREFIX}storesubmit # For store submit files
# BUCKET=${BUCKET_PREFIX}publish # For published binaries
  1. Create bucket policy for CloudFront access:
caution

Replace <CloudFront Distribution ARN From Step 7.7> with the actual CloudFront distribution ARN for each specific bucket.

# Create bucket policy for CloudFront access
cat << EOF > ${BUCKET#${BUCKET_PREFIX}}-bucket-policy.json
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${BUCKET}/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "<CloudFront Distribution ARN From Step 7.7>"
}
}
}
]
}
EOF
  1. Apply the bucket policy:
# Apply the bucket policy
aws s3api put-bucket-policy \
--bucket ${BUCKET} \
--policy file://${BUCKET#${BUCKET_PREFIX}}-bucket-policy.json
  1. Repeat for other buckets by changing the BUCKET variable and running steps 2-3 again.

Step 7.9: Configure DNS

For each CloudFront distribution, create a CNAME record in your domain provider.

  • Create CNAME records in your domain provider for each CloudFront distribution you have created with different CDN domains
    • Name: appcircle-cdn-domain.spacetech.com (replace with your actual CDN domain for each bucket)
    • Type: CNAME
    • Value: <CloudFront Distribution Domain Name> (replace with your actual CloudFront Distribution Domain Name for each bucket)

Create Kubernetes/OpenShift Secret for Access Keys

  • Create the namespace that Appcircle server will be installed in if you haven't yet:
kubectl create namespace appcircle
  • Create a Kubernetes secret named <helm-release-name>-minio-connection with your S3-compatible access and secret keys:
kubectl create secret generic appcircle-server-minio-connection \
-n appcircle \
--from-literal=accessKey=<YOUR_ACCESS_KEY> \
--from-literal=secretKey=<YOUR_SECRET_KEY>
caution
  • Replace appcircle with your actual namespace or project if different.
  • Replace <YOUR_ACCESS_KEY> and <YOUR_SECRET_KEY> with your actual access and secret keys.
  • Replace appcircle-server-minio-connection with <helm-release-name>-minio-connection. Appcircle documentation uses appcircle-server as the release name.

Configure Helm Values

Configure your values.yaml file to use AWS S3 instead of MinIO.

Add the following configuration to your values.yaml file:

global:
minio:
url: https://s3.us-east-1.amazonaws.com # Replace with your AWS S3 endpoint
region: "us-east-1" # Replace with your AWS region
useHttp: "false" # Set to "false" if you're using HTTPS S3 endpoint
bucketPrefix: "appcircle-spacetech-"
resource:
s3:
clientProvider: "AWS" # Set to "AWS" to use AWS S3
minio:
enabled: false # Disable internal MinIO deployment
caution
  • Replace https://s3.us-east-1.amazonaws.com with your AWS S3 endpoint.
  • Replace us-east-1 with your AWS region.
  • Set useHttp to true only if you're using HTTP instead of HTTPS (not recommended for production).
  • Replace appcircle-spacetech- with your actual bucket prefix. If you haven't terminated the terminal session, you can run echo $BUCKET_PREFIX to get the bucket prefix.

Next Steps

After completing the AWS S3 configuration:

  1. Return to the main installation guide:

  2. Continue with the installation process using your configured values.yaml file

  3. Verify the configuration by checking that Appcircle server can access the S3 buckets after installation

Need help?

Get help from Appcircle's support team, or see how others are using Appcircle by joining our Slack Channel.

Preview of Slack