Acro Standards
Effective: May 19th, 2020
01 - Architecture
1.01 - Changes approved by senior developer
All new modules or large changes must be approved by a senior developer.
1.02 - Senior developers may enforce design decisions
Senior developers may enforce a mandatory architecture or design documentation.
02 - Data
02.00 - Classification
In the context of an agency that builds web applications, data typically falls into one of 3 categories:
Public data
Data which is freely accessible to anyone, and can be redistributed without consequence. Examples include:
- public website content
- public policy documents
- public SSH keys
- public SSL/TLS certificates
- product data
- usage metrics
- log files which don't contain any personally identifiable information
- public repository source code
- DNS records
Private data
Data which should only be accessed by specific roles or groups of people, which would have low to moderate consequences if exposed to unauthorized parties. Examples include:
- privileged website content
- inter-office communications
- reports
- business plans
- customer data (email addresses, names, postal addresses, aka Personally Identifiable Information)
- order fulfillment data
- log files containing identifying information
- database exports that don't contain sensitive data
- Private repository source code
Protection of private data is typically accomplished with simple controls, e.g. password protected areas of websites, linux permissions for files, firewalls for network traffic.
Private data typically does not need to be encrypted at rest, but does need to be encrypted in transit.
Most private data is not considered sensitive in general, though some clients may require some of it to be treated as such.
Sensitive data
Data which should only be accessed by specific individuals, roles, or systems. This type of data can have high or extreme (legal, operational, or monetary) consequences if exposed to unauthorized parties. Examples of sensitive data include:
- social insurance numbers
- credit card and cardholder data
- critical business documents
- scans or photos of personal identification
- API keys
- private SSL/TLS keys
- private SSH keys
- access credentials
- proprietary research
- documents protected by provincial, state, or federal regulations.
- operating system snapshots and backups
Sensitive data, especially that which belongs to parties other than the ones handling it, may be subject to legal or regulatory handling requirements (e.g. HIPAA, GDPR, PCI, SOC 2).
Sensitive data typically requires multiple factors of protection, including being encrypted at rest and in transit.
02.01 - Protection of data at rest
One question to ask when protecting sensitive data is: Does the data in question to be handled? Does it need to be stored? If a solution (which meets the business requirements) can be built where data does not need to be handled or stored, that solution is preferable over one which goes to great lengths to protect the data.
Sensitive data may only be stored in version control or in a database if the following conditions are met: * The data must be encrypted with strong cryptography (e.g. AES 256) * The decryption key must not reside on the same system as the encrypted data
Sensitive data stored in Drupal as content should be protected with the Encryption + Key modules, along with a module that stores the key offsite, such as Lockr or AWS KMS.
If a Drupal module requires storage of access credentials to function or communicate with other systems, those credentials should be stored in the environment's settings.local.php file instead of the database. This keeps database exports to be shared without leaking sensitive information, and allows the credentials to be safely encrypted in a separate infrastructure repository. To set values in settings files instead of the database or config files, see https://docs.drupalcommerce.org/commerce2/developer-guide/payments/overriding-payment-config and https://dropsolid.com/en/blog/drupal-8-config-management-part-1.
Sensitive data stored in version control should only ever reside in an infrastructure repository (not a Drupal repository) and must be encrypted with Ansible Vault.
Sensitive data stored in a Lagoon application should be manually loaded into secrets, which are scoped only to the project, environment, and runtime context that needs them.
Sensitive data stored in a Kubernetes application should be manually loaded into Secrets, which are scoped only to the namespace and runtime context that needs them.
Unprotected access credentials or api keys which have been stored in a database or version control are considered compromised, and should be replaced with those that have never been weakly protected.
Unprotected sensitive data stored in a database may be considered breached, depending on how long it has remained unprotected. The immediate step to take is to encrypt the data. Then the project's team lead should evaluate next steps according to Acro's Information Security policy and Data Breach procedure.
Sensitive data required for system operations must only be accessible to the linux user(s) that require access to it. For example: * A site's settings.local.php file must only be accessible to that virtual host's linux owner and PHP users, and the file must not be world readable. * A SSL private key file must only be readable by the root user, and must not be world readable.
If backups are being stored outside of the system they came from, the storage medium must enforce strict access restrictions, and must automatically encrypt the objects at rest. (e.g. EBS disk-level encryption, or S3 bucket or object level encryption).
If backups are being stored on disk, they must be root:root
-owned and not world-readable.
02.02 - Sharing database exports
Just as passwords should not be shared directly, developers should not share database dumps with each other directly.
Each developer should store or retrieve dumps in the appropriate Acro Developer S3 bucket using their own AWS IAM credentials.
02.03 - UTF-8 support
utf8mb4 or equivalent UTF-8 support should be in use in all databases. Without it, certain characters may not save correctly, and may even cause an SQL exception.
For example, a customer using emoji in a message during checkout or using multi-byte characters in their name may prevent them from making their purchase.
The Drupal 7 status report page will show whether a site has proper UTF-8 support or not. See https://www.drupal.org/node/2754539 for information on converting Drupal 7 to support UTF-8.
02.04 - Personally identifiable information
This section is deprecated. See "02.00 - Classification" above.
02.05 - Protection of data in transit
Public or Private data may be transmitted within the same trusted network using plain text protocols, but if the data is being passed across the internet, it must be done so using strong encryption. Examples of trusted private networks are: a 192.168.0.0/16
or 10.0.0.0/8
subnet, or natively-encrypted VPN connection. A local docker compose or lando virtual network is also considered private, as long as its network connections are not in running "host" mode.
Q: Why does public data need to be encrypted in transit?
A: When data is transmitted over plain text protocols, it is subject to tampering by intermediate parties. So even data has no consequence from being shared, it's integrity is not guaranteed when making the trip in plain text. Thus, any plain text network communication across the internet should only exist to facilitate transition to a stronger transfer protocol. For example, it is usually necessary for a web server to listen on port 80 to redirect plain HTTP client requests over to a TLS encrypted HTTPS connection.
Sensitive data must always be transmitted using strong encryption protocols, no matter where the source or destination.
A lando or docker compose application running on a developer's own workstation does not need to encrypt data between docker containers, as long as the network interfaces are not running in "Host" mode. If network interfaces are running in "host" mode, the previously mentioned rules for data transmission apply.
02.06 - Transfer protocols
The following protocols are considered insecure, and should not be used if needing to transmit data securely: * Plain HTTP * Plain FTP * Plain SMTP * Telnet * SSL v3 or lower * TLS 1.1 or lower * SSH lower than version 2 * Plain MySQL / Postgres connections
As of this writing, the acceptable protocols for secure data transfer are: * HTTPS using TLS 1.2 or better. Consult Mozilla's reference page at https://wiki.mozilla.org/Security/Server_Side_TLS for the most up to date TLS version and cipher information * SSH v2 with RSA (2048 bit) or Ed25519 public key authentication. * SFTP (which is essentially SSH) * Rsync (which is essentially SSH) * FTP over TLS * SMTP over TLS * MySQL / Postgres over TLS
02.06 - Credentials storage and distribution
The credentials storage service used and approved by Acro Media supports individual private vaults, role-based access, facilitates secure sharing with authorized parties, supports full document storage, and provides full audit logging. Therefore no employee should be using word documents, plain text files, or other insecure methods for long term storage of access credentials or passwords.
Credentials must never be shared via chat or email. If credentials need to be shared with an authorized party, and that party does not have access (or cannot be granted access) to the vault in question, a 1-time access link can be provided to that authorized party.
Clients who do not have access to a particular vault, and need to share credentials with Acro Media, can securely do so by either: * creating a Google document and sharing it with one specific Acro employee, or * submitting a file to Acro Media's wetransfer account: https://acromedia.wetransfer.com/. The employee who was given the credentials should transfer the credentials to a new entry in Acro's password storage service, and then discard and/or destroy the copy that was provided by the client.
03 - Documentation
03.01 - Project READMEs
All projects must contain a root level README. This README should describe the project and how to set it up.
03.02 - Module READMEs
All custom modules must contain a README that meets the Drupal spec.
03.03 - API Documentation
All custom API endpoints must be documented using OpenAPI. All
custom API endpoints must have .http
files that demonstrate their authentication and
payloads. If possible, also use and include example environment variables and .gitignore
entries to avoid committing local variables.
04 - Developer Experience
04.01 - Developer Environments
Project must provide an automated development environment such as Docker Compose. The current recommended solution is Lando.
04.02 - Development Environment Documentation
Setup steps must be documented in the project README should be as simple as possible.
04.03 - Example local settings file
Local development configuration should have reasonable defaults in a default.settings.local.php file or equivalent.
05 - Continuous Integration
05.01 - Continuous Integration (automated build and deployment process) is mandatory
Projects must use continuous integration for deployments.
See our templates at https://git.acromedia.com/acro/code/standards.
Some clients may have their own setup such as GitHub and Travis CI, but usually we use the Acro GitLab server for all of this.
05.02 - Continuous Integration must be blocked with static and dynamic analysis
Projects must use continuous integration for any tests * Simpletest or PHPUnit tests. * Code standards * Security checks like SensioLabs security-checker.
06 - Drupal modules
06.01 - Share modules on Drupal.org
All modules to be shared on drupal.org except client-specific modules or patches that are not relevant to anyone else or contain specific business logic.
06.02 - All contrib not suitable for drupal.org should still be public.
Use one of our public options * Acro GitLab.com * Acro GitHub
06.03 - All modules must have README and install
All modules must be built as full modules with README files and a proper install process, regardless of if they are client specific or community-shared.
06.04 - All modules must use properly formatted configuration
All modules must use configuration that is properly formatted; there should be no unnecessary hardcoding of configurable values. Proper formatting includes following all conventions of defining the configuration, regardless of tool. In the case of Drupal 8+, this means all configuration MUST have schema defined. Where it makes sense, UI can be used to expose configurations for clients to manipulate, but UI is not required.
06.05 - Module directory structure
Modules in a project should place contrib modules in a contrib directory and custom ones - committed directly to the project instead of a separate repository - in a custom directory. Existing projects do not have to move existing modules but may use those directories for new modules.
06.06 - Building projects
Projects should be built by scripts where possible instead of committing to version control. Contrib modules and other dependencies should be installed by a build process - such as composer install - rather than committed to version control directly.
06.07 - Update Hooks
Update hooks should be done sequentially based on the current state of your active branch, conflicts should be resolved only when merged upstream. Do not anticipate and try to guess ahead, if code is merged in an order different than that initially intended, hooks will be missed.
07 - Performance
07.01 - Homepage performance
The website homepage must load in under 5 seconds. Test it in continuous integration with commercebot.
07.02 - Caching
All core caching options must be enabled. * Page Cache. * Dynamic Page Cache. * BigPipe. * CSS/JS Aggregation.
07.03 - Advanced Aggregation must be used
The Advanced Aggregation module must be installed and configured.
08 - Quality
08.01- Full PHPCS Drupal Standard compliance
Custom code must not have errors using the project's phpcs standard. Custom code should not have warings. The Drupal standard from the coder module should be used but may be modified. Code that is not a Drupal module or theme may choose another standard, like a PSR coding standard or one from another project relevant to the code.
08.02 - Error logs
Log must not have recurring notices and warnings. For example, undefined indexes and other problems that PHP may ignore must be fixed whether they're causing a user-facing issue or not.
08.03 - Minimize technical debt
Projects must have a score under 5 as measured by phpdebt.
09 - Security
09.01 - Update dependencies
Drupal and dependencies must be the latest secure version. This includes composer and npm dependencies.
All Security checks of third-party dependencies are blockers to final deployments. For dependencies managed by composer, SensioLabs has a service for checking dependencies https://security.symfony.com/.
09.02 - Secrets management
All admin accounts must be stored in password management. All passwords that are Acro-controlled must be unique with a high entropy / password strength and should only be generated using the 1password built in generator (avoid online password generators).
Non-Acro hosted sites must have SSH access in password management.
PCI sensitive information must be stored in PCI vault with limited access.
09.03 - SSH and GPG
SSH access keys must be ED25519 if supported, or RSA 4096 bit if ED25519 is not available.
GPG keys must expire within two years.
09.04 - Shell scripts
Shell scripts must follow technical best practices from https://google.github.io/styleguide/shell.xml and http://redsymbol.net/articles/unofficial-bash-strict-mode/. Google's organizational policies, like "When to use Shell" are not necessarily required but are a good idea.
Shell scripts must be tested by shellcheck.
10 - Testing
10.01 - Automated tests
Any automated tests must both run and pass via CI.
Team Leads may enforce more rigid standards or specific testing requirements.
10.02 - Custom module test coverage 50%
Custom modules must have 50% test coverage.
11 - Version Control
11.01 - Version control
All projects must be managed in version control.
11.02 - Patches
All patches should be handled by composer. See https://github.com/cweagans/composer-patches. Patches may be included in “patches” directory if using Drupal 7 and not composer.
11.03 - Package management
All projects must be package managed (ie, by composer, yarn, or an equivalent).
11.04 - Signed Commits with GPG key
All commits must be verified using a GPG key.
11.05 - Dependency versions
Modules and other dependencies may not use the -dev version without specifying the hash to check out. The technical lead on a project must approve use of -dev modules. The reason for using a -dev dependency must be documented in the project so it can be moved to a stable release when the problem is resolved.
11.06 Flow
All projects must follow the structure and deployment models of Gitlab Flow with Environment Branches
11.07 Feature Branches
Changes that you hope to one day push live. can be named anything.
Best practice is to name the branch with the issue number first with a dash and short description of what it is. 117-registration
is good. add_custom_registrationv2
is not. Create a merge request from inside a GitLab issue and it'll do this for you.
11.08 Development Branches
main (master in some legacy repos) is the development branch, pre-production version, the branch where features get merged and development deployments are commonplace.
Only deployment maintenance, CI maintenance, and build step maintenance can be committed directly to main (master in some legacy repos). All other work should be in a feature branch and go through a merge request review with at least 1 approval from a peer.
11.09 Development environment branches
If needed, multiple development deployments could be named deploy/devN where N is a whole number.
11.10 UAT Branch
deploy/uat is the world-viewable test environment. Only deploy/devN or main (master in some legacy repos) merges into this branch.
If you need more than one call them deploy/uatN where N is a whole number. If more than one UAT needs to launch at the same time a final uat that includes the full release is required before deployment.
Small fixes to features that are being tested can be merged directly but MUST be brought back down the stack as quickly as possible.
11.11 Production Branch
deploy/prod is the final live production website. Only deploy/uat merges into this branch.
Hotfixes can be merged directly to deploy/prod but MUST be brought back down the stack as quickly as possible.
11.12 Security Practices: Avoid Committing Sensitive Data
Do not commit passwords, API keys, or other sensitive information to git repositories.