Deployment guide

OpenAS2 4.14.0

Overview

OpenAS2 is an open source Java implementation of the AS2 protocol (RFC 4130), the standard way trading partners exchange EDI and other business documents over the internet. Every message is signed with the sender's key and encrypted for the receiver, and the receiver returns a signed receipt (an MDN) that proves delivery.

This guide covers the OpenAS2 4.14.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud SFTP and file server listing on AWS Marketplace, which you select as the software version when you subscribe and launch. OpenAS2 watches an outbox directory per partner, sends what you drop there, and writes what partners send you to an inbox directory.

The image is built from the OpenAS2 4.14.0 source release, which includes the fixes for a pre-authentication SQL injection through the Message-ID header and a Message-ID path traversal that affect releases before 4.9.0. Upstream's defaults are built for a trusted test network, so the SecureAnyCloud image changes them.

What you get:

  • TLS from the first boot. OpenAS2's receivers listen on loopback only. nginx serves them on port 10443 with a certificate generated on your instance's first boot: https://<your-host>:10443/as2 for AS2 messages and https://<your-host>:10443/mdn for asynchronous receipts. A request for any host name the instance does not serve is dropped.
  • Unsigned messages refused. A message that is not signed by a partner whose certificate you have imported is rejected with signed-message-required. A message for an AS2 ID you have not configured is rejected too. Nothing is stored for either.
  • Nothing shared between instances. Upstream ships a demo keystore with live private keys (password testas2), demo AS2 IDs (MyCompany_OID, PartnerA_OID) and a demo database. None of them is on the image. First boot generates this instance's AS2 IDs, its AS2 keystore (RSA 3072), its passwords and its message tracking database.
  • Closed until first boot, and fail-closed. OpenAS2 cannot start without the files that first boot creates, and nginx ships switched off. First boot starts OpenAS2 on loopback, opens the TLS listener, then proves a signed and encrypted AS2 message and its receipt through nginx. If anything fails, the listener is closed again.
  • Hardened defaults. OpenAS2 runs as its own unprivileged account in a systemd sandbox that can write only to its message store and logs. OpenAS2 and nginx are both blocked from the instance metadata service, and the AMI requires IMDSv2. No management console, REST API or database network port is enabled.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: OpenAS2 4.14.0 in /opt/openas2 with its configuration in /etc/openas2, the OpenJDK 17 runtime, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.

Prerequisites

  • An AWS account subscribed to the listing, an EC2 key pair, and a VPC subnet with a route to the internet (or a private route that your partners use).
  • A security group that allows TCP 22 (SSH) from your own networks and TCP 10443 (AS2 over TLS) from your trading partners' addresses.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select OpenAS2 4.14.0 on Ubuntu 24.04 as the software version, pick your Region, and choose Launch through EC2.

Choose m5.large, your key pair and a security group as described above. Messages, receipts and the tracking database live on the root volume, so size it for the documents you keep.

To launch with the AWS CLI instead, replace the values in angle brackets:

aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
  --instance-type m5.large --key-name <your-key-pair> \
  --security-group-ids <your-security-group> --subnet-id <your-subnet> \
  --metadata-options HttpTokens=required,HttpEndpoint=enabled \
  --block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=30,VolumeType=gp3}' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=openas2}]'
2

Connect to your instance

Connect to OpenAS2 4.14.0 on Ubuntu 24.04 as the SSH user ubuntu:

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

On first boot the instance creates its keys, passwords and database, starts OpenAS2, opens nginx and proves an AS2 exchange. This takes about half a minute. Confirm that it finished:

systemctl is-active openas2 nginx openas2-firstboot
sudo test -f /var/lib/sac/data/openas2-firstboot.done && echo FIRSTBOOT_DONE
active active active FIRSTBOOT_DONE

Only SSH and nginx listen on public addresses. The two OpenAS2 receivers listen on loopback:

sudo ss -lntp | awk 'NR>1 && $4 !~ /127\.0\.0\.(53|54)/ {print $4}' | sort
0.0.0.0:10443 0.0.0.0:22 127.0.0.1:10080 127.0.0.1:10081 [::]:10443 [::]:22
4

Your AS2 details

The instance's details are in a root-only file. Run these commands to show the URLs, AS2 IDs and certificate paths. The passwords in the same file are not printed:

sudo grep -E '^(OPENAS2_|AS2_LOCAL_ID|AS2_LOOPBACK_TEST_ID|AS2_PUBLIC_CERT|TLS_CERT|AS2_KEYSTORE_FILE)' /root/openas2-credentials.txt
sudo grep -oE '^[A-Z0-9_]+PASSWORD=' /root/openas2-credentials.txt
OPENAS2_AS2_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com:10443/as2 OPENAS2_MDN_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com:10443/mdn AS2_LOCAL_ID=sac-<12 hex characters> AS2_LOOPBACK_TEST_ID=sac-<12 hex characters>-loopback AS2_PUBLIC_CERT=/etc/openas2/local-as2-public.cer TLS_CERT=/etc/ssl/openas2/openas2.crt AS2_KEYSTORE_FILE=/etc/openas2/as2_certs.p12 AS2_KEYSTORE_PASSWORD= <set-at-first-boot>= H2_DB_PASSWORD=
  • OPENAS2_AS2_URL is where your trading partners send AS2 messages. OPENAS2_MDN_URL is where they send asynchronous receipts. The host is the instance's public DNS name from EC2 instance metadata, or the IP address when the subnet has no public DNS names. To use your own DNS name, see Step 9.
  • AS2_LOCAL_ID is your AS2 ID. It was generated on this instance, and you can change it to the ID you agree with your partners (Step 7).
  • AS2_PUBLIC_CERT is your AS2 certificate. Partners use it to verify your signatures and to encrypt messages for you.
  • AS2_LOOPBACK_TEST_ID is a second station on the same server. It is used only by the built-in self-test (Step 6).
5

What to give your trading partners

A partner needs your AS2 ID, your AS2 URL and your AS2 certificate. Because the TLS certificate is self-signed, they also need either that certificate or its fingerprint. Print the details:

sudo openssl x509 -noout -subject -enddate -fingerprint -sha256 -in /etc/openas2/local-as2-public.cer
sudo openssl x509 -noout -subject -fingerprint -sha256 -in /etc/ssl/openas2/openas2.crt
subject=O = sac OpenAS2, OU = AS2, CN = sac-<12 hex characters> notAfter=<three years after first boot> GMT sha256 Fingerprint=<AS2 certificate fingerprint> subject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = sac OpenAS2 sha256 Fingerprint=<TLS certificate fingerprint>

Send them the two .cer/.crt files. sudo cat prints them in PEM form, and they contain public keys only.

6

Run the built-in AS2 self-test

The image ships an end-to-end check that you can run at any time. First boot runs it too.

The test sends a real signed and encrypted AS2 message from your station to the self-test station through nginx and TLS. It checks that the payload arrives byte for byte with a signed receipt. It then sends an unsigned message and a message for an unknown AS2 ID through nginx, with a forged X-Forwarded-For header. Both must be refused, nothing may be stored, and OpenAS2 must log the real client address. Run it:

sudo openas2-verify.sh
listeners: 10080/10081 on 127.0.0.1 only, nginx TLS 10443 ; unknown Host/SNI dropped ; GET /as2 403, / 404 ; certificate verifies for ec2-<public-ip-dashed>.compute-1.amazonaws.com round trip: signed+encrypted sac-selftest-<timestamp> local(sac-<id>) -> nginx TLS -> loopback(sac-<id>-loopback) arrived byte-identical; signed MDN 'processed' unsigned message refused (signed-message-required), unknown AS2 ID refused (no partnership, HTTP 500), nothing stored ; OpenAS2 logged the real peer <private-ip>, not the forged X-Forwarded-For OPENAS2_ROUNDTRIP_OK

The test removes the files it created. Its messages stay in the tracking database (Step 10) as a record.

7

Add a trading partner

You need the partner's AS2 ID, their AS2 URL and their AS2 certificate.

Import the certificate into this instance's keystore under an alias of your choice, using lowercase letters, digits, dot, dash or underscore. The tool reads the keystore password itself, so it never appears on a command line, and it restarts OpenAS2:

sudo openas2-import-partner-cert acme ./acme-as2.cer

Next, describe the partner and one partnership per direction in /etc/openas2/partnerships.xml (sudo nano /etc/openas2/partnerships.xml). Your own station is the partner named local. Keep its as2_id, or change it to the ID you agreed with your partners:

<partner name="acme" as2_id="ACME_AS2_ID" x509_alias="acme" email="edi@acme.example"/> <partnership name="local-to-acme"> <sender name="local"/> <receiver name="acme"/> <pollerConfig enabled="true"/> <attribute name="protocol" value="as2"/> <attribute name="as2_url" value="https://as2.acme.example/as2"/> <attribute name="as2_mdn_to" value="edi@your-company.example"/> <attribute name="as2_mdn_options" value="signed-receipt-protocol=optional, pkcs7-signature; signed-receipt-micalg=optional, $attribute.sign$"/> <attribute name="encrypt" value="AES256"/> <attribute name="sign" value="SHA-256"/> <attribute name="resend_max_retries" value="3"/> </partnership> <partnership name="acme-to-local"> <sender name="acme"/> <receiver name="local"/> <attribute name="reject_unsigned_messages" value="true"/> </partnership>

Apply the change by restarting OpenAS2:

sudo systemctl restart openas2

If the partner's AS2 endpoint uses HTTPS with a self-signed certificate, add that certificate to OpenAS2's TLS trust store, /etc/openas2/ssl_trust_certs.p12. The password is SSL_TRUST_KEYSTORE_PASSWORD in the credentials file. A certificate from a public certificate authority needs no extra step.

8

Send and receive files

To send a file to a partner, put it in that partner's outbox directory, which is named after the partner's AS2 ID. OpenAS2 checks the outbox every 5 seconds. It then signs, encrypts and sends the file, and removes it from the outbox:

sudo install -o openas2 -g openas2 -m 0640 ./invoice-1001.edi /var/lib/openas2/data/outbox/ACME_AS2_ID/

Files that cannot be sent are moved to /var/lib/openas2/data/outbox/error/. Received files and receipts are written under /var/lib/openas2/data/<sender ID>-<receiver ID>/, in these directories:

inbox/ Payloads received from partners (decrypted and signature checked)

msgheaders/<date>/ The AS2 headers of each received message

mdn/<date>/ Receipts (MDNs) sent and received

/var/lib/openas2/data/inbox/error/ Messages that were refused, with the reason

Received files are stored under generated names (date, time and a random suffix), never under a name or Message-ID that the sender chose. The original file name is in the matching msgheaders file and in the log.

OpenAS2 logs to /var/log/openas2/openas2.log, with one compressed file per day and 30 days kept:

sudo tail -n 5 /var/log/openas2/openas2.log
9

Use your own DNS name

Point a DNS record at the instance, then set the name your partners use. The command generates a new self-signed TLS certificate for the name and updates nginx, the self-test's trust store, the receipt URL and the URLs in /root/openas2-credentials.txt. It also restarts OpenAS2 and keeps the name across reboots:

sudo openas2-set-hostname as2.your-company.example

Send your partners the new TLS certificate or its fingerprint (Step 5).

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running openas2-set-hostname again replaces it with a self-signed certificate:

sudo install -m 0644 as2.your-company.example.crt /etc/ssl/openas2/openas2.crt
sudo install -m 0600 as2.your-company.example.key /etc/ssl/openas2/openas2.key
sudo nginx -t && sudo systemctl reload nginx

Partners that cannot use port 10443 can reach the instance through a Network Load Balancer that listens on 443 and forwards to 10443.

10

Query the message tracking database

OpenAS2 records the state of every message in an embedded H2 database in /var/lib/openas2/DB, protected by a per-instance password. The embedded database can be opened only while OpenAS2 is stopped. openas2-db reads SQL on standard input and takes the password from the configuration itself:

sudo systemctl stop openas2 echo "SELECT MSG_ID, DIRECTION, STATE, STATUS, CREATE_DT FROM msg_metadata ORDER BY ID DESC LIMIT 5;" | sudo openas2-db
sudo systemctl start openas2
11

Security checks

The configuration and keys are readable only by root and the OpenAS2 account. The passwords exist only in /etc/openas2/openas2.properties and the credentials file. Check the permissions:

sudo stat -c '%a %U:%G %n' /etc/openas2/openas2.properties /etc/openas2/as2_certs.p12 /etc/openas2/ssl_trust_certs.p12 /etc/openas2/partnerships.xml /etc/ssl/openas2/openas2.key /root/openas2-credentials.txt
640 root:openas2 /etc/openas2/openas2.properties 640 root:openas2 /etc/openas2/as2_certs.p12 640 root:openas2 /etc/openas2/ssl_trust_certs.p12 640 root:openas2 /etc/openas2/partnerships.xml 600 root:root /etc/ssl/openas2/openas2.key 600 root:root /root/openas2-credentials.txt

Unsigned messages are refused for every partnership, and the receivers are bound to loopback. Confirm both settings:

sudo grep -oE '(reject_unsigned_messages|module\.AS2(MDN)?ReceiverModule\.http\.address)="[^"]*"' /etc/openas2/config.xml
module.AS2ReceiverModule.http.address="127.0.0.1" module.AS2MDNReceiverModule.http.address="127.0.0.1" reject_unsigned_messages="true"

OpenAS2 runs unprivileged in a sandbox that can write only to its message store and logs. Neither OpenAS2 nor nginx can reach the instance metadata service. Verify the sandbox settings:

systemctl show openas2 -p User -p ProtectSystem -p ReadWritePaths -p NoNewPrivileges -p IPAddressDeny
systemctl show nginx -p IPAddressDeny
IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32 User=openas2 ReadWritePaths=/var/lib/openas2 /var/log/openas2 ProtectSystem=strict NoNewPrivileges=yes IPAddressDeny=fd00:ec2::254/128 168.63.129.16/32 169.254.169.254/32

nginx passes OpenAS2 a fixed host name and the real client address from the connection. OpenAS2 logs the X-Forwarded-For value as the sender's address, so nginx never forwards the value that a client sends:

grep -E 'proxy_set_header (Host|X-Forwarded-For|X-Real-IP)' /etc/nginx/openas2-proxy.conf
proxy_set_header Host $openas2_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr;

Confirm that no per-instance password reached a log, the journal, shell history, backups or any other file:

sudo openas2-secret-leak-check.sh
LEAKCHECK_OK no per-instance password in the journal, /var/log (OpenAS2 and nginx logs included), shell history, MOTD, /var/backups, /etc (only openas2.properties), the OpenAS2 install and state trees, /usr/local or /tmp
12

Server components

Components, with version and path:

OpenAS2 4.14.0 (source tag v4.14.0, commit e97a6a2b) /opt/openas2

OpenJDK runtime 17.0.20.1 /usr/lib/jvm/java-17-openjdk-amd64

H2 database 2.5.252 /opt/openas2/lib/h2-2.5.252.jar

nginx 1.24.0 /etc/nginx/sites-available/sac-openas2

Ubuntu 24.04 LTS

Key paths, with purpose:

/etc/openas2/config.xml OpenAS2 configuration (no passwords in it)

/etc/openas2/openas2.properties Per instance passwords and the receipt URL

/etc/openas2/partnerships.xml Partners and partnerships

/etc/openas2/as2_certs.p12 AS2 keystore: your keys and your partners' certificates

/etc/openas2/local-as2-public.cer Your AS2 certificate

/etc/ssl/openas2/ TLS certificate and key

/var/lib/openas2/data Outboxes, inboxes and receipts

/var/lib/openas2/DB Message tracking database

/var/log/openas2/ OpenAS2 logs

/root/openas2-credentials.txt URLs, AS2 IDs and passwords (mode 0600)

/usr/local/sbin/openas2-verify.sh End-to-end self-test (Step 6)

/usr/local/sbin/openas2-import-partner-cert Import a partner certificate (Step 7)

/usr/local/sbin/openas2-set-hostname Sets the host name and TLS certificate (Step 9)

/usr/local/sbin/openas2-db Query the tracking database (Step 10)

/usr/local/sbin/openas2-secret-leak-check.sh Confirms that no password reached a log

cat /opt/openas2/SOURCE
sudo journalctl -u openas2-firstboot --no-pager -o
cat | grep -E 'Serving as|First boot complete'

Troubleshooting

  • A partner's message is refused with signed-message-required. The partner sent it unsigned. Ask them to sign with SHA-256. Unsigned messages are never accepted.
  • A partner's message is refused with HTTP 500 and "Partnership not found" in the log. The AS2-From / AS2-To IDs do not match a partnership in /etc/openas2/partnerships.xml. Check the IDs on both sides and restart OpenAS2.
  • integrity-check-failed or decryption-failed. The partner's certificate in your keystore, or your certificate on their side, is not the one in use. Re-import theirs (Step 7) and send them yours again (Step 5).
  • The partner's TLS connection is closed straight away. nginx drops requests for host names it does not serve. The partner must use the host in OPENAS2_AS2_URL, one of the instance's IP addresses, or the name you set with openas2-set-hostname.
  • Sending to a partner fails with a certificate error. Their HTTPS certificate is self-signed. Add it to the TLS trust store (Step 7).
  • Nothing answers after launch. Check systemctl status openas2-firstboot and journalctl -u openas2-firstboot. Until first boot completes, the server is deliberately closed.

Security recommendations

  • Allow port 10443 in the security group from your trading partners' addresses only, and port 22 from your own networks only.
  • Keep /root/openas2-credentials.txt and /etc/openas2 secret. Your AS2 private key is in the keystore.
  • If you prefer, remove the self-test station (loopback) and its partnership from partnerships.xml once you no longer need the self-test. It can receive only messages signed with your own key.
  • Renew your AS2 certificate before it expires (three years after first boot) and send the new one to your partners. OpenAS2 supports a fallback certificate during the switch-over (x509_alias_fallback, see the comments in upstream's documentation).
  • Keep the operating system patched. Unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else.
  • Back up /etc/openas2, which holds your keys, to an encrypted location. Back up /var/lib/openas2 for the message history.

Support and licensing

OpenAS2 is open source under the GNU General Public License v3, with no per-user or per-CPU licence fee. The image is built without changes to the OpenAS2 source from the upstream release tag v4.14.0, and the licence text is at /opt/openas2/LICENSE.txt.

The AMI price covers SecureAnyCloud's hardening, first-boot setup and support. OpenAS2 is a trademark of its respective owners. SecureAnyCloud is not affiliated with or endorsed by the OpenAS2 project.

  • Email: sales@secureanycloud.com
  • Website: https://secureanycloud.com
  • Support: 24/7, with a 24 hour response SLA

Deploy on AWS

Launch OpenAS2 4.14.0 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on AWS