├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .idea ├── aws.xml ├── inspectionProfiles │ └── Project_Default.xml ├── vcs.xml └── workspace.xml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── amazon-athena-for-elb ├── Analyzing_ALB_Access_Logs_with_Amazon_Athena.md └── Analyzing_CLB_Access_Logs_with_Amazon_Athena.md ├── application-load-balancer-copy-utility ├── LICENSE ├── README.md └── copy_classic_load_balancer.py ├── application-load-balancer-serverless-app ├── README.md ├── binary_response │ ├── README.md │ ├── binary_response.py │ ├── image1.png │ ├── license.txt │ └── template.yaml ├── helloworld │ ├── README.md │ ├── helloworld.py │ ├── license.txt │ └── template.yaml ├── uploadfile_to_s3 │ ├── README.md │ ├── license.txt │ ├── template.yaml │ └── uploadfile.py └── whatismyip │ ├── README.md │ ├── app.jpg │ ├── license.txt │ ├── template.yaml │ ├── whatismyip.py │ └── whatismyip_template.html ├── classic-load-balancer-consolelink-utility ├── README.md ├── consolelink_classic_load_balancer.py └── images │ ├── ConsoleLinkCSV.png │ └── ConsoleLinkHTML.png ├── elb_ip_monitoring ├── README.md ├── elb_ip_monitoring.yml └── images │ ├── cw-namespace.png │ ├── ip_monitoring-diagram.jpg │ ├── metric-example.png │ ├── per-elb-dimension.png │ └── stack-parameters.png ├── images └── ELB.png ├── log-analysis-elb-cdk-cf-template ├── LICENSE ├── README.md ├── app.py ├── cdk.json ├── config.ini ├── images │ ├── ELBLogAnalysis.png │ ├── disable-acl.png │ ├── step1.png │ ├── step2.png │ └── step3.png ├── requirements.txt ├── stacks │ ├── __init__.py │ └── athena_stack.py └── templates │ ├── alb_logs.yaml │ ├── clb_logs.yaml │ └── nlb_logs.yaml ├── network-load-balancer-copy-utility ├── LICENSE ├── README.md └── copy_network_load_balancer.py ├── proprot ├── LICENSE.txt ├── README.md ├── latest-jar │ └── proprot-1.0.jar ├── pom.xml ├── src │ └── com │ │ └── amazonaws │ │ └── proprot │ │ ├── CRC32CInputStream.java │ │ ├── CRC32COutputStream.java │ │ ├── Generator.java │ │ ├── Header.java │ │ ├── InputAssist.java │ │ ├── InvalidHeaderException.java │ │ ├── NullHasher.java │ │ ├── Parser.java │ │ ├── ProxyProtocol.java │ │ ├── ProxyProtocolSpec.java │ │ ├── Scrap.jpage │ │ ├── Tlv.java │ │ ├── TlvAdapter.java │ │ ├── TlvRaw.java │ │ ├── TlvRawAdapter.java │ │ ├── TlvSubTypeRaw.java │ │ ├── TlvSubTypeRawAdapter.java │ │ └── Util.java └── tst │ └── com │ └── amazonaws │ └── proprot │ ├── CRC32CInputStreamTest.java │ ├── CRC32COutputStreamTest.java │ ├── Compatibility_AwsNetworkLoadBalancerTest.java │ ├── GeneratorTest.java │ ├── HeaderTest.java │ ├── InputAssistTest.java │ ├── NullHasherTest.java │ ├── ParserTest.java │ ├── ProxyProtocolSpecTest.java │ ├── ProxyProtocolTest.java │ ├── TlvRawAdapterTest.java │ └── TlvSubTypeRawAdapterTest.java ├── scheduler-lcu-reservation ├── README.md ├── capacity-scheduler.drawio ├── capacity-scheduler.drawio.png └── templates │ └── capacity-reservation-scheduler.yml └── sharding ├── README.md ├── elb_sharding.yml └── images ├── sharding-diagram.jpg ├── sharding-route53.png └── stack-parameters.png /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | *Issue #, if available:* 2 | 3 | *Description of changes:* 4 | 5 | 6 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java template 2 | # Compiled class file 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.nar 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | ### Python template 27 | # Byte-compiled / optimized / DLL files 28 | __pycache__/ 29 | *.py[cod] 30 | *$py.class 31 | 32 | # C extensions 33 | *.so 34 | 35 | # Distribution / packaging 36 | .Python 37 | build/ 38 | develop-eggs/ 39 | dist/ 40 | downloads/ 41 | eggs/ 42 | .eggs/ 43 | lib/ 44 | lib64/ 45 | parts/ 46 | sdist/ 47 | var/ 48 | wheels/ 49 | share/python-wheels/ 50 | *.egg-info/ 51 | .installed.cfg 52 | *.egg 53 | MANIFEST 54 | 55 | # PyInstaller 56 | # Usually these files are written by a python script from a template 57 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 58 | *.manifest 59 | *.spec 60 | 61 | # Installer logs 62 | pip-log.txt 63 | pip-delete-this-directory.txt 64 | 65 | # Unit test / coverage reports 66 | htmlcov/ 67 | .tox/ 68 | .nox/ 69 | .coverage 70 | .coverage.* 71 | .cache 72 | nosetests.xml 73 | coverage.xml 74 | *.cover 75 | *.py,cover 76 | .hypothesis/ 77 | .pytest_cache/ 78 | cover/ 79 | 80 | # Translations 81 | *.mo 82 | *.pot 83 | 84 | # Django stuff: 85 | *.log 86 | local_settings.py 87 | db.sqlite3 88 | db.sqlite3-journal 89 | 90 | # Flask stuff: 91 | instance/ 92 | .webassets-cache 93 | 94 | # Scrapy stuff: 95 | .scrapy 96 | 97 | # Sphinx documentation 98 | docs/_build/ 99 | 100 | # PyBuilder 101 | .pybuilder/ 102 | target/ 103 | 104 | # Jupyter Notebook 105 | .ipynb_checkpoints 106 | 107 | # IPython 108 | profile_default/ 109 | ipython_config.py 110 | 111 | # pyenv 112 | # For a library or package, you might want to ignore these files since the code is 113 | # intended to run in multiple environments; otherwise, check them in: 114 | # .python-version 115 | 116 | # pipenv 117 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 118 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 119 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 120 | # install all needed dependencies. 121 | #Pipfile.lock 122 | 123 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 124 | __pypackages__/ 125 | 126 | # Celery stuff 127 | celerybeat-schedule 128 | celerybeat.pid 129 | 130 | # SageMath parsed files 131 | *.sage.py 132 | 133 | # Environments 134 | .env 135 | .venv 136 | env/ 137 | venv/ 138 | ENV/ 139 | env.bak/ 140 | venv.bak/ 141 | 142 | # Spyder project settings 143 | .spyderproject 144 | .spyproject 145 | 146 | # Rope project settings 147 | .ropeproject 148 | 149 | # mkdocs documentation 150 | /site 151 | 152 | # mypy 153 | .mypy_cache/ 154 | .dmypy.json 155 | dmypy.json 156 | 157 | # Pyre type checker 158 | .pyre/ 159 | 160 | # pytype static type analyzer 161 | .pytype/ 162 | 163 | # Cython debug symbols 164 | cython_debug/ 165 | 166 | ### Java template 167 | # Compiled class file 168 | *.class 169 | 170 | # Log file 171 | *.log 172 | 173 | # BlueJ files 174 | *.ctxt 175 | 176 | # Mobile Tools for Java (J2ME) 177 | .mtj.tmp/ 178 | 179 | # Package Files # 180 | *.jar 181 | *.war 182 | *.nar 183 | *.ear 184 | *.zip 185 | *.tar.gz 186 | *.rar 187 | 188 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 189 | hs_err_pid* 190 | 191 | # IntelliJ project files 192 | .idea 193 | 194 | # User-specific stuff 195 | .idea/**/workspace.xml 196 | .idea/**/tasks.xml 197 | .idea/**/usage.statistics.xml 198 | .idea/**/dictionaries 199 | .idea/**/shelf 200 | 201 | # AWS User-specific 202 | .idea/**/aws.xml 203 | 204 | # Generated files 205 | .idea/**/contentModel.xml 206 | 207 | *.iml 208 | out 209 | gen 210 | ### Python template 211 | # Byte-compiled / optimized / DLL files 212 | __pycache__/ 213 | *.py[cod] 214 | *$py.class 215 | 216 | # C extensions 217 | *.so 218 | 219 | # Distribution / packaging 220 | .Python 221 | build/ 222 | develop-eggs/ 223 | dist/ 224 | downloads/ 225 | eggs/ 226 | .eggs/ 227 | lib/ 228 | lib64/ 229 | parts/ 230 | sdist/ 231 | var/ 232 | wheels/ 233 | share/python-wheels/ 234 | *.egg-info/ 235 | .installed.cfg 236 | *.egg 237 | MANIFEST 238 | 239 | # PyInstaller 240 | # Usually these files are written by a python script from a template 241 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 242 | *.manifest 243 | *.spec 244 | 245 | # Installer logs 246 | pip-log.txt 247 | pip-delete-this-directory.txt 248 | 249 | # Unit test / coverage reports 250 | htmlcov/ 251 | .tox/ 252 | .nox/ 253 | .coverage 254 | .coverage.* 255 | .cache 256 | nosetests.xml 257 | coverage.xml 258 | *.cover 259 | *.py,cover 260 | .hypothesis/ 261 | .pytest_cache/ 262 | cover/ 263 | 264 | # Translations 265 | *.mo 266 | *.pot 267 | 268 | # Django stuff: 269 | *.log 270 | local_settings.py 271 | db.sqlite3 272 | db.sqlite3-journal 273 | 274 | # Flask stuff: 275 | instance/ 276 | .webassets-cache 277 | 278 | # Scrapy stuff: 279 | .scrapy 280 | 281 | # Sphinx documentation 282 | docs/_build/ 283 | 284 | # PyBuilder 285 | .pybuilder/ 286 | target/ 287 | 288 | # Jupyter Notebook 289 | .ipynb_checkpoints 290 | 291 | # IPython 292 | profile_default/ 293 | ipython_config.py 294 | 295 | # pyenv 296 | # For a library or package, you might want to ignore these files since the code is 297 | # intended to run in multiple environments; otherwise, check them in: 298 | # .python-version 299 | 300 | # pipenv 301 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 302 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 303 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 304 | # install all needed dependencies. 305 | #Pipfile.lock 306 | 307 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 308 | __pypackages__/ 309 | 310 | # Celery stuff 311 | celerybeat-schedule 312 | celerybeat.pid 313 | 314 | # SageMath parsed files 315 | *.sage.py 316 | 317 | # Environments 318 | .env 319 | .venv 320 | env/ 321 | venv/ 322 | ENV/ 323 | env.bak/ 324 | venv.bak/ 325 | 326 | # Spyder project settings 327 | .spyderproject 328 | .spyproject 329 | 330 | # Rope project settings 331 | .ropeproject 332 | 333 | # mkdocs documentation 334 | /site 335 | 336 | # mypy 337 | .mypy_cache/ 338 | .dmypy.json 339 | dmypy.json 340 | 341 | # Pyre type checker 342 | .pyre/ 343 | 344 | # pytype static type analyzer 345 | .pytype/ 346 | 347 | # Cython debug symbols 348 | cython_debug/ 349 | 350 | # Mac 351 | .DS_Store -------------------------------------------------------------------------------- /.idea/aws.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 59 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 1.1.1 4 | * bugfix: Correctly handle classic load balancers that have stickyness disabled and no other policy 5 | 6 | ## 1.1.0 7 | * feature: Support Cookie Based Stickiness 8 | * bugfix: Correctly handle tags with `aws:` reserved namespace https://github.com/aws/elastic-load-balancing-tools/issues/6 9 | 10 | ## 1.0.0 11 | * Initial Release 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check [existing open](https://github.com/aws/elastic-load-balancing-tools/issues), or [recently closed](https://github.com/aws/elastic-load-balancing-tools/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels ((enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any ['help wanted'](https://github.com/aws/elastic-load-balancing-tools/labels/help%20wanted) issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](https://github.com/aws/elastic-load-balancing-tools/blob/master/LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | 61 | We may ask you to sign a [Contributor License Agreement (CLA)](http://en.wikipedia.org/wiki/Contributor_License_Agreement) for larger changes. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Elastic Load Balancing Tools 2 | 3 | ![ELB](images/ELB.png) 4 | 5 | [Elastic Load Balancing (ELB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/userguide/what-is-load-balancing.html) automatically distributes incoming application traffic across Amazon EC2 instances,containers, or resources identified by IP addresses. 6 | 7 | The types of ELB are: 8 | 9 | - ALB - Application Load Balancer 10 | - NLB - Network Load Balancer 11 | - GWLB - Gateway Load Balancer 12 | - CLB - Classic Load Balancer 13 | 14 | Elastic Load Balancing Tools is a collection of utilities, tutorials and code samples to help AWS customers with their use of Elastic Load Balancing. 15 | 16 | 17 | [Classic Load Balancer to Application Load Balancer copy utility](application-load-balancer-copy-utility/)
18 | [Classic Load Balancer to Network Load Balancer copy utility](network-load-balancer-copy-utility/)
19 | [Classic Load Balancer Console Link utility](classic-load-balancer-consolelink-utility/)
20 | [Proxy Protocol v2 implementation Java library](proprot/)
21 | [Step by step for Log Analysis with Amazon Athena](amazon-athena-for-elb/)
22 | [CDK & CloudFormation samples for Log Analysis with Amazon Athena](log-analysis-elb-cdk-cf-template/)
23 | [CloudFormation template for IP monitoring for Classic and Application Load Balancers](elb_ip_monitoring/)
24 | [CloudFormation template for Sharding](sharding/)
25 | [LCU reservation scheduler](scheduler-lcu-reservation/)
-------------------------------------------------------------------------------- /amazon-athena-for-elb/Analyzing_ALB_Access_Logs_with_Amazon_Athena.md: -------------------------------------------------------------------------------- 1 | # Analyzing ALB Access Logs with Amazon Athena 2 | This document includes an overview of setting up Amazon Athena and table creation for Elastic Load Balancing log analysis. 3 | 4 | > For a CDK & CloudFormation sample that deploys this solution: https://github.com/aws/elastic-load-balancing-tools/blob/master/log-analysis-elb-cdk-cf-template 5 | 6 | Setup steps: 7 | 1. Setup AWS account, ELB + enable access logs 8 | 2. Configure your S3 bucket for Athena access 9 | 3. Setup your new database and table refer to https://docs.aws.amazon.com/athena/latest/ug/application-load-balancer-logs.html#create-alb-table for the latest query to create the table 10 | ```sql 11 | CREATE EXTERNAL TABLE IF NOT EXISTS alb_logs ( 12 | type string, 13 | time string, 14 | elb string, 15 | client_ip string, 16 | client_port int, 17 | target_ip string, 18 | target_port int, 19 | request_processing_time double, 20 | target_processing_time double, 21 | response_processing_time double, 22 | elb_status_code string, 23 | target_status_code string, 24 | received_bytes bigint, 25 | sent_bytes bigint, 26 | request_verb string, 27 | request_url string, 28 | request_proto string, 29 | user_agent string, 30 | ssl_cipher string, 31 | ssl_protocol string, 32 | target_group_arn string, 33 | trace_id string, 34 | domain_name string, 35 | chosen_cert_arn string, 36 | matched_rule_priority string, 37 | request_creation_time string, 38 | actions_executed string, 39 | redirect_url string, 40 | error_reason string, 41 | new_field string, 42 | classification string, 43 | classification_reason string 44 | ) 45 | ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' 46 | WITH SERDEPROPERTIES ( 47 | 'serialization.format' = '1', 48 | 'input.regex' = 49 | '([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" \"([^\"]*)\" ([A-Z0-9-]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\" \"([^\"]*)\"($| \"[^ ]*\")(.*)') 50 | LOCATION 's3://your-alb-logs-directory/AWSLogs//elasticloadbalancing/region'; 51 | ``` 52 | 4. Run queries 53 | ### Select data information for time period 54 | ```sql 55 | SELECT client_ip, 56 | count(client_ip) AS requestCount, 57 | avg(received_bytes+sent_bytes) AS avgTransactionSize, 58 | sum(received_bytes+sent_bytes) AS totalBytes 59 | FROM alb_logs 60 | WHERE time > '2018-11-01' 61 | AND time < '2018-11-29' 62 | GROUP BY client_ip 63 | ORDER BY requestCount DESC limit 10; 64 | ``` 65 | ### View total data processed for time period 66 | ```sql 67 | SELECT count(client_ip) AS totalRequestCount, 68 | avg(received_bytes+sent_bytes) AS avgTransactionSize, 69 | sum(received_bytes+sent_bytes) AS totalBytes 70 | FROM alb_logs 71 | WHERE time > '2018-11-29' 72 | AND time < '2018-12-01'; 73 | ``` 74 | ### Select request IPs 75 | ```sql 76 | SELECT DISTINCT client_ip 77 | FROM alb_logs limit 100; 78 | ``` 79 | ### Get top 100 clients by request count 80 | ```sql 81 | SELECT client_ip, 82 | count(client_ip) AS ct 83 | FROM alb_logs 84 | GROUP BY client_ip 85 | ORDER BY ct DESC limit 100; 86 | ``` 87 | #### plus response+request size 88 | ```sql 89 | SELECT client_ip, 90 | count(client_ip) AS requestCount, 91 | avg(received_bytes+sent_bytes) AS avgTransactionSize 92 | FROM alb_logs 93 | GROUP BY client_ip 94 | ORDER BY requestCount DESC limit 100; 95 | ``` 96 | ### Ciphers by use 97 | ```sql 98 | SELECT DISTINCT ssl_cipher, 99 | count(ssl_cipher) AS cipherCount 100 | FROM alb_logs 101 | GROUP BY ssl_cipher limit 100; 102 | ``` 103 | ### Last 30 Day Ciphers and TLS Version by use 104 | ```sql 105 | SELECT DISTINCT ssl_cipher AS TLSCipher, 106 | ssl_protocol AS TLSVersion, 107 | count(ssl_cipher) AS TLSCipherCount 108 | FROM alb_logs 109 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 110 | AND NOT ssl_protocol = '-' 111 | GROUP BY ssl_cipher,ssl_protocol 112 | ORDER BY TLSCipherCount DESC 113 | ``` 114 | ### Top 100 backends 115 | ```sql 116 | SELECT target_ip AS backend, 117 | count(target_ip) AS count, 118 | avg(received_bytes)+avg(sent_bytes) AS avgTransactionSize 119 | FROM alb_logs 120 | GROUP BY target_ip 121 | ORDER BY count DESC limit 100; 122 | ``` 123 | ### Summary of ELB 124 | ```sql 125 | SELECT count(1) AS requests, 126 | count(1)/date_diff('second',date_parse(min(time),'%Y-%m-%dT%H:%i:%s.%fZ'),date_parse(max(time),'%Y-%m-%dT%H:%i:%s.%fZ')) AS requestPerSecond,avg(received_bytes + sent_bytes) AS avg_requestSize_bytes, min(time) AS startTime, max(time) AS endTime 127 | FROM alb_logs; 128 | ``` 129 | ### Summary of Non-Compliant HTTP Requests 130 | ```sql 131 | SELECT COUNT(1) AS requests, 132 | request_verb, 133 | classification, 134 | classification_reason 135 | FROM alb_logs 136 | GROUP BY request_verb, classification, classification_reason 137 | LIMIT 100; 138 | ``` 139 | -------------------------------------------------------------------------------- /amazon-athena-for-elb/Analyzing_CLB_Access_Logs_with_Amazon_Athena.md: -------------------------------------------------------------------------------- 1 | # Analyzing ALB Access Logs with Amazon Athena 2 | This document includes an overview of setting up Amazon Athena and table creation for Elastic Load Balancing log analysis. 3 | 4 | > For a CDK & CloudFormation sample that deploys this solution: https://github.com/aws/elastic-load-balancing-tools/blob/master/log-analysis-elb-cdk-cf-template 5 | 6 | Setup steps: 7 | 1. Setup AWS account, ELB + enable access logs 8 | 2. Configure your S3 bucket for Athena access 9 | 3. Setup your new database and table refer to https://docs.aws.amazon.com/athena/latest/ug/elasticloadbalancer-classic-logs.html#create-elb-table for the latest query to create the table 10 | ```sql 11 | CREATE EXTERNAL TABLE IF NOT EXISTS clb_logs ( 12 | request_timestamp string, 13 | elb_name string, 14 | request_ip string, 15 | request_port int, 16 | backend_ip string, 17 | backend_port int, 18 | request_processing_time double, 19 | backend_processing_time double, 20 | response_processing_time double, 21 | elb_response_code string, 22 | backend_response_code string, 23 | received_bytes bigint, 24 | sent_bytes bigint, 25 | request_verb string, 26 | url string, 27 | protocol string, 28 | user_agent string, 29 | ssl_cipher string, 30 | ssl_protocol string 31 | ) 32 | ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' 33 | WITH SERDEPROPERTIES ( 34 | 'serialization.format' = '1', 35 | 'input.regex' = '([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:\-]([0-9]*) ([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) ([-0-9]*) ([-0-9]*) \\\"([^ ]*) ([^ ]*) (- |[^ ]*)\\\" (\"[^\"]*\") ([A-Z0-9-]+) ([A-Za-z0-9.-]*)$' ) 36 | LOCATION 's3://your_log_bucket/prefix/AWSLogs/AWS_account_ID/elasticloadbalancing/'; 37 | ``` 38 | 4. Run queries 39 | ### Select data information for time period 40 | ```sql 41 | SELECT client_ip, 42 | count(client_ip) AS requestCount, 43 | avg(received_bytes+sent_bytes) AS avgTransactionSize, 44 | sum(received_bytes+sent_bytes) AS totalBytes 45 | FROM clb_logs 46 | WHERE time > '2018-11-01' 47 | AND time < '2018-11-29' 48 | GROUP BY client_ip 49 | ORDER BY requestCount DESC limit 10; 50 | ``` 51 | ### View total data processed for time period 52 | ```sql 53 | SELECT count(client_ip) AS totalRequestCount, 54 | avg(received_bytes+sent_bytes) AS avgTransactionSize, 55 | sum(received_bytes+sent_bytes) AS totalBytes 56 | FROM clb_logs 57 | WHERE time > '2018-11-29' 58 | AND time < '2018-12-01'; 59 | ``` 60 | ### Select request IPs 61 | ```sql 62 | SELECT DISTINCT client_ip 63 | FROM clb_logs limit 100; 64 | ``` 65 | ### Get top 100 clients by request count 66 | ```sql 67 | SELECT client_ip, 68 | count(client_ip) AS ct 69 | FROM clb_logs 70 | GROUP BY client_ip 71 | ORDER BY ct DESC limit 100; 72 | ``` 73 | #### plus response+request size 74 | ```sql 75 | SELECT client_ip, 76 | count(client_ip) AS requestCount, 77 | avg(received_bytes+sent_bytes) AS avgTransactionSize 78 | FROM clb_logs 79 | GROUP BY client_ip 80 | ORDER BY requestCount DESC limit 100; 81 | ``` 82 | ### Ciphers by use 83 | ```sql 84 | SELECT DISTINCT ssl_cipher, 85 | count(ssl_cipher) AS cipherCount 86 | FROM clb_logs 87 | GROUP BY ssl_cipher limit 100; 88 | ``` 89 | ### Top 100 backends 90 | ```sql 91 | SELECT target_ip AS backend, 92 | count(target_ip) AS count, 93 | avg(received_bytes)+avg(sent_bytes) AS avgTransactionSize 94 | FROM clb_logs 95 | GROUP BY target_ip 96 | ORDER BY count DESC limit 100; 97 | ``` 98 | ### Summary of ELB 99 | ```sql 100 | SELECT count(1) AS requests, 101 | count(1)/date_diff('second',date_parse(min(time),'%Y-%m-%dT%H:%i:%s.%fZ'),date_parse(max(time),'%Y-%m-%dT%H:%i:%s.%fZ')) AS requestPerSecond,avg(received_bytes + sent_bytes) AS avg_requestSize_bytes, min(time) AS startTime, max(time) AS endTime 102 | FROM clb_logs; 103 | ``` -------------------------------------------------------------------------------- /application-load-balancer-copy-utility/README.md: -------------------------------------------------------------------------------- 1 | ## Classic load balancer to Application load balancer copy utility 2 | 3 | ### Overview: 4 | Customers can utilize this tool to copy the configuration of their existing Classic load balancer to create a new Application load balancer with the same configuration. Customers can also choose to register their existing backend EC2 instances with the new Application load balancer. 5 | 6 | ### Usage: 7 | ``` 8 | copy_classic_load_balancer.py 9 | --name 10 | --region 11 | [--profile ] 12 | [--debug ] 13 | [--register-targets] 14 | [--dry-run] 15 | ``` 16 | 17 | Example 1: Test whether the load balancer configuration is supported 18 | ``` 19 | copy_classic_load_balancer.py --name my-load-balancer --region us-west-2 --dry-run 20 | ``` 21 | 22 | Example 2: Create an Application load balancer based on the specified Classic load balancer but do not register the instances as targets 23 | ``` 24 | copy_classic_load_balancer.py --name my-load-balancer -–region us-west-2 25 | ``` 26 | 27 | Example 3: Create an Application load balancer based on the specified Classic load balancer and register the instances as targets 28 | ``` 29 | copy_classic_load_balancer.py --name my-load-balancer -–region us-west-2 --register-targets 30 | ``` 31 | 32 | ### Unsupported Configurations: 33 | 1. Classic load balancer has TCP or SSL listeners 34 | 2. Classic load balancer is in EC2-Classic 35 | 3. Classic load balancer has only one enabled subnet 36 | 4. Classic load balancer has TCP or SSL health check configured 37 | 5. Classic load balancer has an unsupported policy (please note that this utility does not currently support Application-Controlled Session Stickiness) 38 | 6. Classic load balancer has more than 50 unique backend ports 39 | 7. Classic load balancer has more than 10 listeners 40 | 41 | ### Addition considerations and best practices: 42 | 1. If you are utilizing Auto Scaling groups (ASG) you will need to register the ASG with the respective target groups. 43 | 2. All HTTPS listeners created will be utilizing the AWS pre-defined cipher security policy. Please modify the HTTPS listener configurations if you need to use custom policies. 44 | 3. If you are utilizing Amazon EC2 Container Service (ECS) you will need to associate your ECS service with the new Application load balancer. 45 | 4. We recommend testing your application on the Application load balancer before migrating your traffic using DNS. Amazon Route 53 weighted resource record sets let you associate multiple resources with a single DNS name. Using these weighted resource record sets, you can gradually shift your traffic from your Classic load balancer to your new Application load balancer after testing is complete. For more information about weighted routing please see: 46 | http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html#routing-policy-weighted. For Instructions on creating Resource Record Sets by Using the Amazon Route 53 Console are, please see: 47 | http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-editing.html 48 | 49 | For more information please see the Application load balancer Documentation: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html 50 | 51 | ### License 52 | The Classic load balancer to Application load balancer copy utility is licensed under the Apache 2.0 License. 53 | 54 | 55 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/README.md: -------------------------------------------------------------------------------- 1 | ## Application Load Balancer Serverless App 2 | 3 | Application Load Balancer (ALB) can now trigger Lambda functions to serve HTTP/HTTPS requests enabling users to access serverless applications from the web browsers or mobile applications. This is an AWS Serverless Application Repository enables you to quickly deploy AWS Lambda functions that work with Application Load Balancer. 4 | 5 | [More demo of Lambda as target on Application Load Balancer](https://exampleloadbalancer.com/lambda_demo.html) 6 | 7 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/binary_response/README.md: -------------------------------------------------------------------------------- 1 | # ALB-Lambda-Target-HelloWorld 2 | 3 | A sample Lambda function template that works with Application Load Balancer. It reads a local .png image file, encodes the image data through base64, put the data into an HTTP response and sends it to the client. 4 | 5 | [More demo of Lambda as target on Application Load Balancer](https://exampleloadbalancer.com/lambda_demo.html) 6 | ## TO DEPLOY 7 | ``` 8 | aws cloudformation package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket <<>> 9 | aws cloudformation deploy --template-file serverless-output.yaml --stack-name <<>> --capabilities CAPABILITY_IAM 10 | ``` 11 | 12 | ##Register Lambda to your Application Load Balancer 13 | Create a target group, which is used in request routing. If the request content matches a listener rule with an action to forward it to this target group, the load balancer invokes the registered Lambda function. 14 | To create a target group and register the Lambda function 15 | 16 | 1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/]((https://aws.amazon.com/serverless)). 17 | 18 | 2. On the navigation pane, under **LOAD BALANCING**, choose **Target Groups**. 19 | 20 | 3. Choose **Create target group**. 21 | 22 | 4. For **Target group name**, type a name for the target group. 23 | 24 | 5. For **Target type**, select **Lambda function**. 25 | 26 | 6. Register the Lambda function that is deployed earlier after you create the target group 27 | 28 | ## License 29 | 30 | Apache License 2.0 (Apache-2.0) 31 | 32 | Made with ❤️ by AWS Elastic Load Balancing. Available on the [AWS Serverless Application Repository](https://aws.amazon.com/serverless) -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/binary_response/binary_response.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | 4 | def lambda_handler(event, context): 5 | print('\n==event==') 6 | print(event) 7 | 8 | response = { 9 | "statusCode": 200, 10 | "statusDescription": "200 OK", 11 | "isBase64Encoded": True, 12 | "headers": { 13 | "Content-Type": "image/png;" 14 | } 15 | } 16 | 17 | with open("./image1.png", "rb") as imageFile: 18 | raw_data = imageFile.read() 19 | encoded_data = base64.b64encode(raw_data) 20 | 21 | response['body']=encoded_data 22 | return response 23 | 24 | 25 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/binary_response/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/application-load-balancer-serverless-app/binary_response/image1.png -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/binary_response/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: BinaryResponse Lambda function template for Application Load Balancer Lambda as target 4 | 5 | Outputs: 6 | BinaryResponseFunctionARN: 7 | Description: "ARN of the BinaryResponse Lambda function" 8 | Value: !GetAtt BinaryResponseFunction.Arn 9 | 10 | 11 | Resources: 12 | BinaryResponseFunction: 13 | Type: AWS::Serverless::Function 14 | Properties: 15 | Description: An Application Load Balancer Lambda Target that sends a .png image to the client. 16 | Handler: binary_response.lambda_handler 17 | Runtime: python3.8 18 | CodeUri: ./ 19 | Timeout: 300 20 | 21 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/helloworld/README.md: -------------------------------------------------------------------------------- 1 | # ALB-Lambda-Target-HelloWorld 2 | 3 | A sample Lambda function template that works with Application Load Balancer. It returns plain text "Hello World from Lambda" when it is triggered. 4 | 5 | [More demo of Lambda as target on Application Load Balancer](https://exampleloadbalancer.com/lambda_demo.html) 6 | ## TO DEPLOY 7 | ``` 8 | aws cloudformation package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket <<>> 9 | aws cloudformation deploy --template-file serverless-output.yaml --stack-name <<>> --capabilities CAPABILITY_IAM 10 | ``` 11 | 12 | ## Register Lambda to your Application Load Balancer 13 | Create a target group, which is used in request routing. If the request content matches a listener rule with an action to forward it to this target group, the load balancer invokes the registered Lambda function. 14 | To create a target group and register the Lambda function 15 | 16 | 1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/]((https://aws.amazon.com/serverless)). 17 | 18 | 2. On the navigation pane, under **LOAD BALANCING**, choose **Target Groups**. 19 | 20 | 3. Choose **Create target group**. 21 | 22 | 4. For **Target group name**, type a name for the target group. 23 | 24 | 5. For **Target type**, select **Lambda function**. 25 | 26 | 6. Register the Lambda function that is deployed earlier after you create the target group 27 | 28 | 29 | ## License 30 | 31 | Apache License 2.0 (Apache-2.0) 32 | 33 | Made with ❤️ by AWS Elastic Load Balancing. Available on the [AWS Serverless Application Repository](https://aws.amazon.com/serverless) 34 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/helloworld/helloworld.py: -------------------------------------------------------------------------------- 1 | def lambda_handler(event, context): 2 | response = { 3 | "statusCode": 200, 4 | "statusDescription": "200 OK", 5 | "isBase64Encoded": False, 6 | "headers": { 7 | "Content-Type": "text/html; charset=utf-8" 8 | } 9 | } 10 | 11 | response['body'] = """ 12 | 13 | Hello World! 14 | 21 | 22 | 23 |

Hello World from Lambda

24 | 25 | """ 26 | return response -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/helloworld/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: HelloWorld Lambda function template for Application Load Balancer Lambda as target 4 | 5 | Outputs: 6 | HelloWorldFunctionARN: 7 | Description: "ARN of the HelloWorld Lambda function" 8 | Value: !GetAtt HelloWorldFunction.Arn 9 | 10 | 11 | Resources: 12 | HelloWorldFunction: 13 | Type: AWS::Serverless::Function 14 | Properties: 15 | Description: An Application Load Balancer Lambda Target that returns "HelloWorld" 16 | Handler: helloworld.lambda_handler 17 | Runtime: python3.8 18 | CodeUri: ./ 19 | Timeout: 300 20 | 21 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/uploadfile_to_s3/README.md: -------------------------------------------------------------------------------- 1 | # ALB-Lambda-Target-UploadFiletoS3 2 | 3 | A sample Lambda function template that works with Application Load Balancer. You can upload a binary file (e.g. an image or video file) to your S3 bucket with a **POST** request to trigger this Lambda function through your Application Load Balancer. 4 | 5 | 6 | You need to use query string parameter to specify the S3 bucket , S3 Object Key (file name) that the Lambda function can use to upload the file as an object to S3. 7 | 8 | For example, to upload an image file -- logo.png as test.png to the S3 bucket -- myBucket: 9 | 10 | ``` 11 | curl -ivv -X POST -H "Content-Type: image/png" -F "data=@logo.png" "http(s)://<>?objectname=test.png&bucketname=myBucket" 12 | ``` 13 | 14 | 15 | *Note: This template creates an IAM role that the Lambda function can assume to upload files to S3. Please adjust the IAM role for your own use case.* 16 | 17 | [More demo of Lambda as target on Application Load Balancer](https://exampleloadbalancer.com/lambda_demo.html) 18 | ## TO DEPLOY 19 | ``` 20 | aws cloudformation package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket <<>> 21 | aws cloudformation deploy --template-file serverless-output.yaml --stack-name <<>> --capabilities CAPABILITY_IAM 22 | ``` 23 | 24 | ##Register Lambda to your Application Load Balancer 25 | Create a target group, which is used in request routing. If the request content matches a listener rule with an action to forward it to this target group, the load balancer invokes the registered Lambda function. 26 | To create a target group and register the Lambda function 27 | 28 | 1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/]((https://aws.amazon.com/serverless)). 29 | 30 | 2. On the navigation pane, under **LOAD BALANCING**, choose **Target Groups**. 31 | 32 | 3. Choose **Create target group**. 33 | 34 | 4. For **Target group name**, type a name for the target group. 35 | 36 | 5. For **Target type**, select **Lambda function**. 37 | 38 | 6. Register the Lambda function that is deployed earlier after you create the target group 39 | 40 | 41 | ## License 42 | 43 | Apache License 2.0 (Apache-2.0) 44 | 45 | Made with ❤️ by AWS Elastic Load Balancing. Available on the [AWS Serverless Application Repository](https://aws.amazon.com/serverless) 46 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/uploadfile_to_s3/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: UploadFiletoS3 Lambda function template for Application Load Balancer Lambda as target 4 | 5 | Outputs: 6 | UploadFiletoS3FunctionARN: 7 | Description: "ARN of the UploadFiletoS3 Lambda function" 8 | Value: !GetAtt UploadFiletoS3Function.Arn 9 | 10 | 11 | Resources: 12 | UploadFiletoS3Function: 13 | Type: AWS::Serverless::Function 14 | Properties: 15 | Description: An Application Load Balancer Lambda Target that upload files to S3 16 | Handler: uploadfile.lambda_handler 17 | Runtime: python3.8 18 | CodeUri: ./ 19 | Timeout: 300 20 | Role: !GetAtt UploadFiletoS3FunctionRole.Arn 21 | DependsOn: 22 | - UploadFiletoS3FunctionRole 23 | 24 | UploadFiletoS3FunctionRole: 25 | Type: AWS::IAM::Role 26 | Properties: 27 | AssumeRolePolicyDocument: 28 | Version: '2012-10-17' 29 | Statement: 30 | - Effect: Allow 31 | Principal: 32 | Service: 33 | - lambda.amazonaws.com 34 | Action: 35 | - sts:AssumeRole 36 | ManagedPolicyArns: 37 | - arn:aws:iam::aws:policy/AmazonS3FullAccess -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/uploadfile_to_s3/uploadfile.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import boto3 3 | 4 | 5 | def lambda_handler(event, context): 6 | print('\n==event==') 7 | print(event) 8 | 9 | response = { 10 | "statusCode": 200, 11 | "statusDescription": "200 OK", 12 | "isBase64Encoded": False, 13 | "headers": { 14 | "Content-Type": "text/html;" 15 | } 16 | } 17 | encoded_data = event['body'] 18 | S3KEY = event['queryStringParameters']['objectname'] 19 | BUCKET_NAME = event['queryStringParameters']['bucketname'] 20 | LOCALFILE = "/tmp/"+ S3KEY 21 | decoded_data = encoded_data.decode('base64') 22 | 23 | imageFile = open(LOCALFILE, "w") 24 | imageFile.write(decoded_data) 25 | imageFile.close() 26 | 27 | if event['headers']['user-agent']=='ELB-HealthChecker/2.0': 28 | print("This is a Health Check Request") 29 | response['body'] = 'Response to Health Check Request' 30 | return response 31 | if event['httpMethod']=='GET': 32 | response['body'] = 'Reponse to a GET request' 33 | return response 34 | if event['httpMethod']=='POST': 35 | s3 = boto3.resource('s3') 36 | try: 37 | s3.meta.client.upload_file(LOCALFILE, BUCKET_NAME, S3KEY) 38 | response['body'] = "Upload to S3 -- {} successfully".format(BUCKET_NAME) 39 | return response 40 | except Exception as e: 41 | print(e) 42 | response['body'] = "Failed to upload to S3 -- {}".format(BUCKET_NAME) 43 | return response 44 | 45 | data = "Default Response" 46 | response['body'] = data 47 | return response 48 | 49 | 50 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/whatismyip/README.md: -------------------------------------------------------------------------------- 1 | # ALB-Lambda-Target-WhatIsMyIP 2 | 3 | A sample Lambda function template that works with Application Load Balancer. It returns a page with client's source IP address when it is triggered. 4 | 5 | You can also use query string parameter to specify the output format. 6 | 7 | For example, you can get text output by using query string -- "?output=text": 8 | ``` 9 | curl -ivv "http(s)://<>?output=text 10 | ``` 11 | You can also get JSON by using query string -- "?output=json" 12 | ``` 13 | curl -ivv "http(s)://<>?output=json 14 | ``` 15 | 16 | 17 | [More demo of Lambda as target on Application Load Balancer](https://exampleloadbalancer.com/lambda_demo.html) 18 | ## TO DEPLOY 19 | ``` 20 | aws cloudformation package --template-file template.yaml --output-template-file serverless-output.yaml --s3-bucket <<>> 21 | aws cloudformation deploy --template-file serverless-output.yaml --stack-name <<>> --capabilities CAPABILITY_IAM 22 | ``` 23 | 24 | ##Register Lambda to your Application Load Balancer 25 | Create a target group, which is used in request routing. If the request content matches a listener rule with an action to forward it to this target group, the load balancer invokes the registered Lambda function. 26 | To create a target group and register the Lambda function 27 | 28 | 1. Open the Amazon EC2 console at [https://console.aws.amazon.com/ec2/]((https://aws.amazon.com/serverless)). 29 | 30 | 2. On the navigation pane, under **LOAD BALANCING**, choose **Target Groups**. 31 | 32 | 3. Choose **Create target group**. 33 | 34 | 4. For **Target group name**, type a name for the target group. 35 | 36 | 5. For **Target type**, select **Lambda function**. 37 | 38 | 6. Register the Lambda function that is deployed earlier after you create the target group 39 | 40 | ## How does it look like 41 | ![](https://github.com/renlon/elastic-load-balancing-tools/blob/master/application-load-balancer-serverless-app/whatismyip/app.jpg) 42 | 43 | ## License 44 | 45 | Apache License 2.0 (Apache-2.0) 46 | 47 | Made with ❤️ by AWS Elastic Load Balancing. Available on the [AWS Serverless Application Repository](https://aws.amazon.com/serverless) -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/whatismyip/app.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/application-load-balancer-serverless-app/whatismyip/app.jpg -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/whatismyip/template.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Transform: AWS::Serverless-2016-10-31 3 | Description: WhatismyIP Lambda function template for Application Load Balancer Lambda as target 4 | 5 | Outputs: 6 | WhatismyIPFunctionArn: 7 | Description: "WhatismyIPFunctionArn" 8 | Value: !GetAtt WhatismyIPFunction.Arn 9 | 10 | Resources: 11 | WhatismyIPFunction: 12 | Type: AWS::Serverless::Function 13 | Properties: 14 | Description: An Application Load Balancer Lambda Target that returns the source IP address of the client 15 | Handler: whatismyip.lambda_handler 16 | Runtime: python3.8 17 | CodeUri: ./ 18 | Timeout: 60 19 | 20 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/whatismyip/whatismyip.py: -------------------------------------------------------------------------------- 1 | import time 2 | import json 3 | import os 4 | 5 | TEMPLATE = './whatismyip_template.html' 6 | 7 | 8 | def lambda_handler(event, context): 9 | print('==event==') 10 | print(event) 11 | with open(TEMPLATE, 'rw') as template: 12 | template_html = template.read() 13 | 14 | response = { 15 | "statusCode": 200, 16 | "headers": { 17 | "Content-Type": "text/html;" 18 | }, 19 | "isBase64Encoded": False 20 | } 21 | if event['headers']['user-agent'] == 'ELB-HealthChecker/2.0': 22 | print('HealthCheck Request') 23 | data = 'Response to HealthCheck' 24 | response['body'] = data 25 | return response 26 | 27 | sourceip_list = event['headers']['x-forwarded-for'].split(',') 28 | if sourceip_list: 29 | sourceip = str(sourceip_list[0]) 30 | data = "

Your IP is {}

".format(sourceip) 31 | if event['queryStringParameters'] == {"output":"text"}: 32 | response['body']=sourceip 33 | return response 34 | if event['queryStringParameters'] == {"output":"json"}: 35 | response['body'] = json.dumps({"Source IP":sourceip}) 36 | return response 37 | else: 38 | data = '

No source IP found

' 39 | response_html = template_html.replace("", data) 40 | return response_html 41 | 42 | 43 | print(type(template_html)) 44 | response_html = template_html.replace("", data) 45 | 46 | response['body'] = response_html 47 | print(response) 48 | return response 49 | 50 | 51 | -------------------------------------------------------------------------------- /application-load-balancer-serverless-app/whatismyip/whatismyip_template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | AWS Elastic Load Balancer Demos 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | 20 |

What is my IP? Powered by Lambda as a target on Application Load Balancer.

21 |
22 |

More demos of Lambda as Target on Application Load Balancer

23 |
24 | 25 |
26 |

27 | 28 |

29 | AWS Cloud 30 |

You can also get text output by using query string: "?output=text"

31 |

or JSON by using query string: "?output=json"

32 | 33 |
34 | 35 |
36 |
37 | 50 |
51 |
52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /classic-load-balancer-consolelink-utility/README.md: -------------------------------------------------------------------------------- 1 | ## Classic Load Balancer Console Link utility 2 | 3 | ### Overview: 4 | This utility helps create a CSV spreadsheet or a HTML file of Classic Load Balancers' AWS Console URL link along with other attributes -- 'Name', 'DNSName', 'Scheme', 'HostedZoneID', 'CreatedTime', 'VPCId', 'AvailabilityZones', 'EC2Platform', 'Subnets' and 'SecurityGroup'. 5 | 6 | It enable you to search and manage your Classic Load Balancers easily without dealing with pagination through API call or going over page by page through AWS console. 7 | 8 | If you have a big number of Classic Load Balancers, this tool enables you to search and manage your Classic Load Balancers easily without dealing with pagination through API or going over page by page through AWS console. 9 | 10 | 11 | ### Usage: 12 | ``` 13 | consolelink_classic_load_balancer.py 14 | --region 15 | --format 16 | [--debug ] 17 | ``` 18 | 19 | Example 1: Create a CSV spreadsheet of AWS Console URL link for Classic Load Balancers in us-west-2 region 20 | ``` 21 | consolelink_classic_load_balancer.py --region us-west-2 --format csv 22 | ``` 23 | 24 | Example 2: Create a HTML spreadsheet of AWS Console URL link for Classic Load Balancers in us-west-2 region 25 | ``` 26 | consolelink_classic_load_balancer.py --region us-west-2 --format html 27 | ``` 28 | 29 | ### CSV File: 30 | ![CSV](images/ConsoleLinkCSV.png) 31 | 32 | 33 | ### HTML File: 34 | ![HTML](images/ConsoleLinkHTML.png) 35 | 36 | 37 | ### License 38 | The Classic Load Balancer Console Link utility is licensed under the Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0 39 | 40 | -------------------------------------------------------------------------------- /classic-load-balancer-consolelink-utility/consolelink_classic_load_balancer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2016. Amazon Web Services, Inc. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # Import the SDK and required libraries 17 | import boto3 18 | import logging 19 | import argparse 20 | import sys 21 | import botocore 22 | import csv 23 | 24 | # Classic Load Balancer Console Link utility 25 | # version 1.0.0 2017 26 | # Authors: Long Ren 27 | 28 | # This script help create a spreadsheet of Classic Load Balancers' AWS console URL link along with other attributes 29 | # such as 'Name', 'DNSName', 'Scheme', 'HostedZoneID', 'CreatedTime', 30 | # 'VPCId', 'AvailabilityZones', 'EC2Platform', 'Subnets', 'SecurityGroup' 31 | 32 | 33 | # With no parameters or configuration, boto3 looks for access keys here: 34 | # 35 | # 1. Environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY) 36 | # 2. Credentials file (~/.aws/credentials or 37 | # C:\Users\USER_NAME\.aws\credentials) 38 | # 3. AWS IAM role for Amazon EC2 instance 39 | # (http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) 40 | 41 | # Usage: 42 | # classic_load_balancer_console_link.py 43 | # --region 44 | # --format 45 | # [--debug ] 46 | 47 | VERSION = '1.0.0' 48 | CONSOLE_PREFIX = 'https://console.aws.amazon.com/ec2/v2/home?region=' 49 | 50 | # Log will be stored in CLBConsoleLink.log file in the same directory as this utility script 51 | logger = logging.getLogger() 52 | logger.setLevel(logging.INFO) 53 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') 54 | file_handler = logging.FileHandler('CLBConsoleLink.log') 55 | file_handler.setFormatter(formatter) 56 | file_handler.setLevel(logging.DEBUG) 57 | 58 | stream_handler = logging.StreamHandler() 59 | stream_handler.setFormatter(formatter) 60 | stream_handler.setLevel(logging.ERROR) 61 | 62 | logger.addHandler(file_handler) 63 | logger.addHandler(stream_handler) 64 | 65 | 66 | def get_elb_data(region): 67 | """ 68 | Describe the Classic Load Balancer and retrieve attributes 69 | """ 70 | if debug: 71 | logger.debug("Getting existing Classic Load Balancer data") 72 | elbc = boto3.client('elb', region_name=region) 73 | # Describes the specified Classic Load Balancer. 74 | try: 75 | paginator = elbc.get_paginator('describe_load_balancers') 76 | except botocore.exceptions.ClientError as e: 77 | logger.error(e.response['Error']['Message']) 78 | elb_data = [] 79 | for describe_load_balancers in paginator.paginate(): 80 | # Render a dictionary that contains the Classic Load Balancer attributes 81 | for lb in describe_load_balancers['LoadBalancerDescriptions']: 82 | elb_item = {} 83 | elb_item['DNSName'] = lb['DNSName'] 84 | elb_item['Scheme'] = lb['Scheme'] 85 | elb_item['HostedZoneID'] = lb['CanonicalHostedZoneNameID'] 86 | elb_item['Name'] = lb['LoadBalancerName'] 87 | elb_item['ConsoleLink'] = CONSOLE_PREFIX + str(region) + '#LoadBalancers:loadBalancerName=' + lb['LoadBalancerName'] 88 | elb_item['CreatedTime'] = lb['CreatedTime'] 89 | elb_item['AvailabilityZones'] = lb['AvailabilityZones'] 90 | elb_item['BackendInstances'] = lb['Instances'] 91 | # Check if a Classic Load Balancer is in EC2-Classic or EC2-VPC 92 | if not lb['Subnets']: 93 | elb_item['EC2Platform'] = 'EC2-Classic' 94 | elb_item['Subnets'] = None 95 | elb_item['SecurityGroup'] = lb['SourceSecurityGroup']['GroupName'] 96 | elb_item['VPCId'] = None 97 | else: 98 | elb_item['EC2Platform'] = 'EC2-VPC' 99 | elb_item['Subnets'] = lb['Subnets'] 100 | elb_item['SecurityGroup'] = lb['SecurityGroups'] 101 | elb_item['VPCId'] = lb['VPCId'] 102 | elb_data.append(elb_item) 103 | if debug: 104 | logger.debug("elb data:") 105 | logger.debug(elb_data) 106 | return elb_data 107 | 108 | 109 | def get_csv(elb_data): 110 | ''' 111 | Generate a CSV file with Classic Load Balancers' Attributes and ConsoleLink 112 | ''' 113 | fileds = sorted(list(set(k for d in elb_data for k in d))) 114 | with open('CLBConsoleLink.csv', 'wb') as csv_file: 115 | writer = csv.writer(csv_file) 116 | writer.writerow(fileds) 117 | for lb in elb_data: 118 | writer.writerow([lb.get(col, None) for col in fileds]) 119 | writer.writerow([lb.get(col, None) for col in fileds]) 120 | 121 | 122 | def get_html(elb_data): 123 | """ 124 | Generate a html file with Classic Load Balancers' Attributes and ConsoleLink 125 | """ 126 | html = """Classic Load Balancer Console Link""" 127 | colunm_names = sorted(list(set(k for d in elb_data for k in d))) 128 | for colunm in colunm_names: 129 | html += "".format(colunm) 130 | html += "" 131 | for lb in elb_data: 132 | for attribute in ([lb.get(col, None) for col in colunm_names]): 133 | if isinstance(attribute, str): 134 | if CONSOLE_PREFIX in attribute: 135 | html += ''''''.format(attribute, attribute.split('=')[-1]) 136 | else: 137 | html += "".format(attribute) 138 | html = """Classic Load Balancer Console Link
{}
{}{}
""" 139 | column_names = sorted(list(set(k for d in elb_data for k in d))) 140 | for column in column_names: 141 | html += "".format(column) 142 | html += "" 143 | for lb in elb_data: 144 | html += "" 145 | for attribute in ([lb.get(col, None) for col in column_names]): 146 | if isinstance(attribute, str) and (CONSOLE_PREFIX in attribute): 147 | html += ''''''.format(attribute, attribute.split('=')[-1]) 148 | else: 149 | html += "".format(attribute) 150 | html += "" 151 | html += "
{}
{}{}
" 152 | with open('CLBConsoleLink.html', 'w') as html_file: 153 | html_file.write(html) 154 | 155 | 156 | def main(): 157 | """ 158 | Taking in args in main function 159 | """ 160 | parser = argparse.ArgumentParser( 161 | description='Create a Console Link Spreadsheet for ' 162 | 'Classic Load Balancers', usage='%(prog)s --region --format ') 163 | parser.add_argument("--region", help="The region of the Classic Load Balancers " 164 | "that you want to describe", required=True) 165 | parser.add_argument("--format", help="The format of the output file that you " 166 | "want to retrieve. Current " 167 | "supported formats are CSV and HTML", required=True) 168 | parser.add_argument("--debug", help="debug mode", action='store_true') 169 | # if no options, print help 170 | if len(sys.argv[1:]) == 0: 171 | parser.print_help() 172 | parser.exit() 173 | args = parser.parse_args() 174 | region = args.region 175 | format = args.format.lower() 176 | if format != 'csv' and format != 'html': 177 | logger.error('Unsupported output format. The supported ' 178 | 'formats are HTML and CSV') 179 | parser.print_help() 180 | parser.exit() 181 | global debug 182 | debug = args.debug 183 | global client 184 | session = botocore.session.get_session() 185 | session.user_agent_name = 'CLBConsoleLink/' + VERSION 186 | # Obtain Classic Load Balancer data 187 | elb_data = get_elb_data(region) 188 | if format == 'csv': 189 | get_csv(elb_data) 190 | if format == 'html': 191 | get_html(elb_data) 192 | 193 | 194 | if __name__ == '__main__': 195 | main() 196 | -------------------------------------------------------------------------------- /classic-load-balancer-consolelink-utility/images/ConsoleLinkCSV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/classic-load-balancer-consolelink-utility/images/ConsoleLinkCSV.png -------------------------------------------------------------------------------- /classic-load-balancer-consolelink-utility/images/ConsoleLinkHTML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/classic-load-balancer-consolelink-utility/images/ConsoleLinkHTML.png -------------------------------------------------------------------------------- /elb_ip_monitoring/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | This CloudFormation template deploys a solution to publishes a CloudWatch metric indicating the number of IP addresses being used by either an Application or Classic Load Balancer. 4 | 5 | Benefits and use cases of this template include: 6 | - **Subnet sizing** - Knowing how many IPs are used can help you with subnet sizing. 7 | - **Sharding** - Both Classic and Application Load Balancers have an IP address limit of 100 for each load balancer. If consumption approaches this limit, it is advisable to distribute the traffic across multiple load balancers. 8 | 9 | 10 | ## Architecture 11 | 12 | ![Stack Parameters](images/ip_monitoring-diagram.jpg) 13 | 14 | 15 | ## Deployment 16 | 17 | 1. In the AWS Management Console, go to "CloudFormation" and click "Create stack" 18 | 19 | 1. Select "Upload a template file", choose elb_ip_monitoring.yml and click Next 20 | 21 | 1. Fill up the parameters: 22 | - **Stack Name** - Any name to identify the stack 23 | - **CloudWatchNamespace** - Metrics will be pubished inside this CloudWatch Namespace. It is suggested you keep the same namespace for all stacks so you will have a centralized place for all ELB IP monitoring metrics. 24 | - **ELBName** - DNS Name of a single ELB (Application or Classic) 25 | 26 | 1. Click Next and Next again for the stack creation. You will need to acknowledge the creation of an IAM role. The IAM role is used to execute the Lambda function that will resolve the ELB's DNS name and paste the count in a CloudWatch metric. 27 | 28 | ![Stack Parameters](images/stack-parameters.png) 29 | 30 | ## Usage 31 | 32 | Once the stack is created, you can navigate to CloudWatch console and click All metrics and select the Custom namespace with the name you provided when creating the stack: 33 | 34 | ![CloudWatch Namespace](images/cw-namespace.png) 35 | 36 | Then select "Per ELB" Dimension: 37 | 38 | ![Per ELB Dimension](images/per-elb-dimension.png) 39 | 40 | Below the metric showing the number of IPs the load balancer have over a period of time. In the example below, the load balancer has 6 IPs. 41 | 42 | ![Per ELB Dimension](images/metric-example.png) 43 | -------------------------------------------------------------------------------- /elb_ip_monitoring/elb_ip_monitoring.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: CloudFormation template to create a DNS record with a weighted policy pointing to two ELBs. 3 | 4 | Parameters: 5 | ELBName: 6 | Description: DNS Name of Elastic Load Balancer (e.g. my-load-balancer1-1234567890.us-west-2.elb.amazonaws.com) 7 | Type: String 8 | MinLength: '1' 9 | CloudWatchNamespace: 10 | Description: CloudWatch Namespace (e.g. ELBIpMonitoring) 11 | Type: String 12 | MinLength: '1' 13 | Default: 'ELBIpMonitoring' 14 | 15 | Resources: 16 | LambdaRoleELBDNS: 17 | Type: AWS::IAM::Role 18 | Properties: 19 | RoleName: !Sub LambdaRoleELBDNS-${AWS::StackName} 20 | AssumeRolePolicyDocument: 21 | Version: 2012-10-17 22 | Statement: 23 | - Effect: Allow 24 | Principal: 25 | Service: 26 | - lambda.amazonaws.com 27 | Action: 28 | - sts:AssumeRole 29 | Path: / 30 | Policies: 31 | - PolicyName: PutMetricDataPolicy 32 | PolicyDocument: 33 | Version: '2012-10-17' 34 | Statement: 35 | - Effect: Allow 36 | Action: 37 | - cloudwatch:PutMetricData 38 | Resource: '*' 39 | ManagedPolicyArns: 40 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 41 | 42 | LambdaELBDNSResolution: 43 | Type: AWS::Lambda::Function 44 | Properties: 45 | Environment: 46 | Variables: 47 | ELB: !Ref ELBName 48 | NAMESPACE: !Ref CloudWatchNamespace 49 | Code: 50 | ZipFile: | 51 | import os 52 | import socket 53 | import boto3 54 | import botocore 55 | 56 | elb_name = os.environ['ELB'] 57 | elb_short_name = elb_name.split('.')[0] 58 | cw_namespace = os.environ['NAMESPACE'] 59 | 60 | 61 | def dns_resolution(elb_name): 62 | try: 63 | elb_dns_all = f"all.{elb_name}" 64 | result = socket.gethostbyname_ex(elb_dns_all) 65 | address_list = result[2] 66 | return len(address_list) 67 | except socket.gaierror as e: 68 | print(f"An error occurred: {e}") 69 | return 0 70 | 71 | def put_metric_to_cloudwatch(value): 72 | cloudwatch = boto3.client('cloudwatch') 73 | 74 | metric_data = { 75 | 'MetricName': 'IP_Count', 76 | 'Dimensions': [ 77 | { 78 | 'Name': 'Per ELB', 79 | 'Value': elb_short_name 80 | }, 81 | ], 82 | 'Value': value 83 | } 84 | 85 | try: 86 | cloudwatch.put_metric_data( 87 | Namespace=cw_namespace, 88 | MetricData=[metric_data] 89 | ) 90 | print(f"Metric data sent: {value}") 91 | except Exception as e: 92 | print(f"An error occurred: {e}") 93 | 94 | def lambda_handler(event, context): 95 | 96 | results_count = dns_resolution(elb_name) 97 | if results_count > 0: 98 | put_metric_to_cloudwatch(results_count) 99 | else: 100 | print(f"No DNS results for {elb_name}") 101 | 102 | Handler: "index.lambda_handler" 103 | Runtime: python3.11 104 | Timeout: 10 105 | Role: !GetAtt LambdaRoleELBDNS.Arn 106 | 107 | ScheduledRule: 108 | Type: AWS::Events::Rule 109 | Properties: 110 | Description: "ScheduledRule" 111 | ScheduleExpression: "rate(60 minutes)" 112 | State: "ENABLED" 113 | Targets: 114 | - 115 | Arn: 116 | Fn::GetAtt: 117 | - 'LambdaELBDNSResolution' 118 | - "Arn" 119 | Id: "TargetFunctionV1" 120 | 121 | PermissionForEventsToInvokeLambda: 122 | Type: AWS::Lambda::Permission 123 | Properties: 124 | FunctionName: 125 | Ref: "LambdaELBDNSResolution" 126 | Action: "lambda:InvokeFunction" 127 | Principal: "events.amazonaws.com" 128 | SourceArn: 129 | Fn::GetAtt: 130 | - "ScheduledRule" 131 | - "Arn" 132 | -------------------------------------------------------------------------------- /elb_ip_monitoring/images/cw-namespace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/elb_ip_monitoring/images/cw-namespace.png -------------------------------------------------------------------------------- /elb_ip_monitoring/images/ip_monitoring-diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/elb_ip_monitoring/images/ip_monitoring-diagram.jpg -------------------------------------------------------------------------------- /elb_ip_monitoring/images/metric-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/elb_ip_monitoring/images/metric-example.png -------------------------------------------------------------------------------- /elb_ip_monitoring/images/per-elb-dimension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/elb_ip_monitoring/images/per-elb-dimension.png -------------------------------------------------------------------------------- /elb_ip_monitoring/images/stack-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/elb_ip_monitoring/images/stack-parameters.png -------------------------------------------------------------------------------- /images/ELB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/images/ELB.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/README.md: -------------------------------------------------------------------------------- 1 | # ELB Log Analysis 2 | 3 | ## Overview 4 | 5 | This cdk / CloudFormation project aims to make it easy to spin up the resources needed to query ELB logs using Athena/SQL. 6 | 7 | Along with the Glue and Athena resources, it also creates pre-defined queries to help with specific use cases: 8 | 9 | - Find Top Clients / User Agents 10 | - Stats for Target Distribution / Request size / URL hit 11 | - Search for 4xx and 5xx HTTP errors 12 | - Understand TLS protocol / ciphersuite usage 13 | 14 | ### Architecture 15 | 16 | ![diagram](images/ELBLogAnalysis.png) 17 | 18 | ## Using CloudFormation Templates 19 | 20 | Use the following templates: 21 | 22 | - **ALB**: templates/alb_logs.yaml 23 | - **CLB**: templates/clb_logs.yaml 24 | - **NLB**: templates/nlb_logs.yaml 25 | 26 | Provide the Bucket Name where the ELB logs are as a parameter for the CloudFormation template. 27 | 28 | ## Using CDK 29 | 30 | If you are not familiar with AWS CDK, start here: https://docs.aws.amazon.com/cdk/v2/guide/home.html 31 | 32 | ### Set up 33 | 34 | 1 - Clone this repository 35 | 1 - Create and activate a virtualenv: 36 | ``` 37 | python3 -m venv .venv 38 | source .venv/bin/activate 39 | ``` 40 | 1 - Install dependencies: 41 | 42 | ``` 43 | pip install -r requirements.txt 44 | ``` 45 | 46 | 47 | ### Configuring the region: 48 | Edit the file *config.ini* to set your region: 49 | 50 | ``` 51 | [defaults] 52 | region = us-east-1 53 | ``` 54 | 55 | ### Configure credentials 56 | CDK will use the default AWS profile credentials configured in your machine, you can change it or add credentials as environment variables: 57 | ``` 58 | export AWS_ACCESS_KEY_ID= 59 | export AWS_SECRET_ACCESS_KEY= 60 | 61 | Like the example below: 62 | 63 | export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE 64 | export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY 65 | ``` 66 | 67 | ### Run cdk bootstrap 68 | Because the template is larger than 50Kb, *cdk bootstrap* is required, this will create a bucket in the account to facilitate the template upload. 69 | 70 | ```cdk bootstrap``` 71 | 72 | 73 | ### Setting up stacks 74 | 75 | Open the file app.py and edit it as per the instructions below. 76 | 77 | #### Creating a stack : 78 | 79 | ```stack = AthenaStack(app, 'AthenaStack1', env={'region': region})``` 80 | 81 | The line above defines a new stack *AthenaStack1*. To add the actual resources to your stack you must call one of the methods according to the ELB type (athena_alb, athena_clb or athena_nlb), passing the S3 bucket where your ELB access logs are as parameters. 82 | 83 | 84 | *stack.athena_alb(identifier, bucket_name)* 85 | 86 | *stack.athena_clb(identifier, bucket_name)* 87 | 88 | *stack.athena_nlb(identifier, bucket_name)* 89 | 90 | In the example below we are creating three sets of resources, for each type of Load Balancer: 91 | 92 | ``` 93 | stack = AthenaStack(app, 'AthenaStack1', env={'region': region}) 94 | 95 | alb_bucket_name = 'elbstack1-alblogselbstack1b1061897-1wgbmokmrr0me' 96 | stack.athena_alb('main_logs', alb_bucket_name) 97 | 98 | clb_bucket_name = 'elbstack1-clblogselbstack1569130d6-krxi15z4lzxn' 99 | stack.athena_clb('main_logs', clb_bucket_name) 100 | 101 | nlb_bucket_name = 'elbstack1-nlblogselbstack1a07805c6-1ephxwcaha4pc' 102 | stack.athena_nlb('main_logs', nlb_bucket_name) 103 | ``` 104 | 105 | 106 | If you have multiple buckets for same ELB type, you can call same method again for each one of them, just changing the name identifier: 107 | 108 | 109 | ``` 110 | alb_main_bucket_name = 'elbstack1-alblogselbstack1b1061897-1wgbmokmrr0me' 111 | stack.athena_alb('main_logs', alb_main_bucket_name) 112 | 113 | alb_other_bucket_name = 'elbstack1-alblogselbstack1b1061897-1wgbmokmrr0me' 114 | stack.athena_alb('other_logs', alb_other_bucket_name) 115 | ``` 116 | 117 | Cross account support: 118 | 119 | If the account where the bucket with the logs are is different than the account where you are creating this stack, you have to provide the parameter *bucket_account* with the account id of the bucket: 120 | ``` 121 | alb_bucket_name = 'elbstack1-alblogselbstack1b1061897-1wgbmokmrr0me' 122 | stack.athena_alb('main_logs_cross_account', alb_bucket_name, bucket_account='174029014086') 123 | ``` 124 | 125 | See *Cross Account permissions* section below for information on how to set the permissions on the bucket for cross account access. 126 | 127 | 128 | ### Deploy 129 | 130 | To deploy this stack to your default AWS account/region, run: 131 | 132 | ```cdk deploy``` 133 | 134 | ### Usage 135 | Once the stack is deployed sucesfully, open your AWS Console and in the navigation bar search for Athena, open it and observe the select the option as described below and shown in the image. 136 | 137 | 1 - Database should be **db_elb_logs_** 138 | 139 | 2 - Tables should be one per S3 bucket with logs as defined in the app.py file. 140 | 141 | 3 - Select the correct workgroup, should look like **wg_elb_logs_** 142 | 143 | 144 | ![step1](images/step1.png) 145 | 146 | - Next, open the tab "Saved queries" to access the pre-created queries: 147 | 148 | ![step2](images/step2.png) 149 | 150 | - Select the type of query and ELB you want to run, this will open a window like shown below: 151 | 152 | ![step3](images/step3.png) 153 | 154 | - In the window above, you can hit the Run (or Run again) button to execute the query. 155 | 156 | You can also adjust the SQL statement to your needs, for example to change for a larger period (60 days), replace: 157 | 158 | ```WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day``` 159 | 160 | to 161 | 162 | ```WHERE from_iso8601_timestamp(time) > current_timestamp - interval '60' day``` 163 | 164 | ### Cross Account permissions 165 | 166 | To allow cross account access there are two steps: 167 | 168 | 1 - **Disable ACL** 169 | 170 | In the Bucket permissions, select ACLs Disabled: 171 | 172 | ![step3](images/disable-acl.png) 173 | 174 | This will enforce bucket owner as the owner of all objects (log files), otherwise the objects will be owned by ELB Access delivery account and the cross account sharing will not work. 175 | 176 | 177 | 2 - **Add bucket policy statement** 178 | 179 | ``` 180 | { 181 | "Sid": "CrossAccount", 182 | "Effect": "Allow", 183 | "Principal": { 184 | "AWS": "arn:aws:iam:::root" 185 | }, 186 | "Action": [ 187 | "s3:GetObject", 188 | "s3:ListBucket" 189 | ], 190 | "Resource": [ 191 | "arn:aws:s3:::", 192 | "arn:aws:s3:::/AWSLogs//*" 193 | ] 194 | } 195 | ``` 196 | Replace , and 197 | 198 | source_account_id is the account where the Athena Stack is going to be created. 199 | 200 | ### License 201 | 202 | This project is licensed under the Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0 . -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from configparser import ConfigParser 4 | 5 | # from aws_cdk import core 6 | from aws_cdk import App 7 | 8 | from stacks.athena_stack import AthenaStack 9 | 10 | # Read config.ini file 11 | config_object = ConfigParser() 12 | config_object.read('config.ini') 13 | defaults = config_object['defaults'] 14 | region = defaults['region'] 15 | 16 | app = App() 17 | 18 | 19 | # Define the stack 20 | stack = AthenaStack(app, 'AthenaElbLogStack', env={'region': region}) 21 | stack.template_options.description = 'Athena & Glue resources for ELB Access Logs analysis' 22 | 23 | # Example for ALB 24 | alb_bucket_name = 'my-alb-access-log-s3-bucket' 25 | stack.athena_alb('main_alblogs_bucket1', alb_bucket_name) 26 | 27 | # Example for CLB 28 | clb_bucket_name = 'my-clb-access-log-s3-bucket' 29 | stack.athena_clb('main_clblogs_bucket1', clb_bucket_name) 30 | 31 | # Example for NLB 32 | nlb_bucket_name = 'my-nlb-access-log-s3-bucket' 33 | stack.athena_nlb('main_nlblogs_bucket1', nlb_bucket_name) 34 | 35 | # Example for ALB/ Cross-account, adding bucket_account parameter with the account id 36 | alb_bucket_name = 'my-alb-access-log-s3-bucket-in-otheraccount' 37 | stack.athena_alb('main_logs_cross_account', alb_bucket_name, bucket_account='123456789012') 38 | 39 | # Example with specific prefix in the S3 bucket, add bucket_prefix parameter 40 | alb_bucket_name = 'my-alb-access-log-s3-bucket' 41 | stack.athena_alb('main_logs_cross_account', alb_bucket_name, bucket_prefix='myalb1') 42 | 43 | app.synth() 44 | -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "python3 app.py", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "requirements*.txt", 11 | "source.bat", 12 | "**/__init__.py", 13 | "python/__pycache__", 14 | "tests" 15 | ] 16 | }, 17 | "context": { 18 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": false, 19 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": false, 20 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": false, 21 | "@aws-cdk/core:stackRelativeExports": false 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/config.ini: -------------------------------------------------------------------------------- 1 | [defaults] 2 | region = us-east-1 3 | -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/images/ELBLogAnalysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/images/ELBLogAnalysis.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/images/disable-acl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/images/disable-acl.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/images/step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/images/step1.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/images/step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/images/step2.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/images/step3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/images/step3.png -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/requirements.txt: -------------------------------------------------------------------------------- 1 | attrs>=22.1.0 2 | aws-cdk-lib>=2.43.1 3 | aws-cdk.aws-glue-alpha>=2.43.1a0 4 | cattrs>=22.1.0 5 | constructs>=10.1.114 6 | exceptiongroup>=1.0.0rc9 7 | jsii>=1.68.0 8 | publication>=0.0.3 9 | python-dateutil>=2.8.2 10 | six>=1.16.0 11 | typeguard>=2.13.3 12 | typing_extensions>=4.3.0 -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/stacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/log-analysis-elb-cdk-cf-template/stacks/__init__.py -------------------------------------------------------------------------------- /log-analysis-elb-cdk-cf-template/templates/nlb_logs.yaml: -------------------------------------------------------------------------------- 1 | Description: Athena & Glue resources for ELB Access Logs analysis 2 | 3 | Parameters: 4 | LBLogsBucketName: 5 | Type: String 6 | Description: The name of the Amazon S3 bucket where the ELB Logs are located. 7 | 8 | Resources: 9 | dbelblogsathenaelblogstack637ED423: 10 | Type: AWS::Glue::Database 11 | Properties: 12 | CatalogId: 13 | Ref: AWS::AccountId 14 | DatabaseInput: 15 | Name: !Sub db_elb_logs_${AWS::StackName} 16 | 17 | keylogsathenaAthenaElbLogStack61CFBB92: 18 | Type: AWS::KMS::Key 19 | Properties: 20 | KeyPolicy: 21 | Statement: 22 | - Action: kms:* 23 | Effect: Allow 24 | Principal: 25 | AWS: 26 | Fn::Join: 27 | - "" 28 | - - "arn:" 29 | - Ref: AWS::Partition 30 | - ":iam::" 31 | - Ref: AWS::AccountId 32 | - :root 33 | Resource: "*" 34 | - Action: 35 | - kms:Encrypt 36 | - kms:Decrypt 37 | Effect: Allow 38 | Principal: 39 | AWS: 40 | Fn::Join: 41 | - "" 42 | - - "arn:" 43 | - Ref: AWS::Partition 44 | - ":iam::" 45 | - Ref: AWS::AccountId 46 | - :root 47 | Resource: "*" 48 | Version: "2012-10-17" 49 | Description: Key for ELB Logs Athena - AthenaElbLogStack 50 | EnableKeyRotation: true 51 | UpdateReplacePolicy: Retain 52 | DeletionPolicy: Retain 53 | 54 | elblogsathenaAthenaElbLogStack062B4278: 55 | Type: AWS::S3::Bucket 56 | Properties: 57 | BucketEncryption: 58 | ServerSideEncryptionConfiguration: 59 | - ServerSideEncryptionByDefault: 60 | KMSMasterKeyID: 61 | Fn::GetAtt: 62 | - keylogsathenaAthenaElbLogStack61CFBB92 63 | - Arn 64 | SSEAlgorithm: aws:kms 65 | UpdateReplacePolicy: Retain 66 | DeletionPolicy: Retain 67 | 68 | wgelblogsathenaelblogstack: 69 | Type: AWS::Athena::WorkGroup 70 | Properties: 71 | Name: !Sub wg_elb_logs_${AWS::StackName} 72 | Description: Workgroup for ELB logs 73 | RecursiveDeleteOption: true 74 | State: ENABLED 75 | Tags: 76 | - Key: wg_elb_logs 77 | Value: "True" 78 | WorkGroupConfiguration: 79 | PublishCloudWatchMetricsEnabled: false 80 | RequesterPaysEnabled: false 81 | ResultConfiguration: 82 | OutputLocation: 83 | Fn::Join: 84 | - "" 85 | - - s3:// 86 | - Ref: elblogsathenaAthenaElbLogStack062B4278 87 | - /logs_query_results/ 88 | 89 | tbnlblogsTableDB5703EA: 90 | Type: AWS::Glue::Table 91 | Properties: 92 | CatalogId: 93 | Ref: AWS::AccountId 94 | DatabaseName: 95 | Ref: dbelblogsathenaelblogstack637ED423 96 | TableInput: 97 | Description: !Sub tb_nlb_logs_${LBLogsBucketName} 98 | Name: !Sub tb_nlb_logs_${LBLogsBucketName} 99 | Parameters: 100 | has_encrypted_data: false 101 | projection.day.digits: "2" 102 | projection.day.range: 01,31 103 | projection.day.type: integer 104 | projection.month.digits: "2" 105 | projection.month.range: 01,12 106 | projection.month.type: integer 107 | projection.year.digits: "4" 108 | projection.year.type: integer 109 | projection.year.range: 2017,2035 110 | projection.enabled: "true" 111 | EXTERNAL: "TRUE" 112 | storage.location.template: 113 | Fn::Join: 114 | - "" 115 | - - s3:// 116 | - Ref: LBLogsBucketName 117 | - /AWSLogs/ 118 | - Ref: AWS::AccountId 119 | - /elasticloadbalancing/us-east-1/${year}/${month}/${day} 120 | PartitionKeys: 121 | - Name: year 122 | Type: int 123 | - Name: month 124 | Type: int 125 | - Name: day 126 | Type: int 127 | StorageDescriptor: 128 | Columns: 129 | - Name: type 130 | Type: string 131 | - Name: version 132 | Type: string 133 | - Name: time 134 | Type: string 135 | - Name: elb 136 | Type: string 137 | - Name: listener 138 | Type: string 139 | - Name: client_ip 140 | Type: string 141 | - Name: client_port 142 | Type: int 143 | - Name: destination_ip 144 | Type: string 145 | - Name: destination_port 146 | Type: int 147 | - Name: connection_time 148 | Type: double 149 | - Name: tls_handshake_time 150 | Type: double 151 | - Name: received_bytes 152 | Type: bigint 153 | - Name: sent_bytes 154 | Type: bigint 155 | - Name: incoming_tls_alert 156 | Type: string 157 | - Name: chosen_cert_arn 158 | Type: string 159 | - Name: chosen_cert_serial 160 | Type: string 161 | - Name: tls_cipher 162 | Type: string 163 | - Name: tls_protocol_version 164 | Type: string 165 | - Name: tls_named_group 166 | Type: string 167 | - Name: domain_name 168 | Type: string 169 | - Name: alpn_fe_protocol 170 | Type: string 171 | - Name: alpn_be_protocol 172 | Type: string 173 | - Name: alpn_client_preference_list 174 | Type: string 175 | Compressed: false 176 | InputFormat: org.apache.hadoop.mapred.TextInputFormat 177 | Location: 178 | Fn::Join: 179 | - "" 180 | - - s3:// 181 | - Ref: LBLogsBucketName 182 | - /AWSLogs/ 183 | - Ref: AWS::AccountId 184 | - /elasticloadbalancing/us-east-1 185 | OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat 186 | SerdeInfo: 187 | Parameters: 188 | serialization.format: 1 189 | input.regex: ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) 190 | SerializationLibrary: org.apache.hadoop.hive.serde2.RegexSerDe 191 | StoredAsSubDirectories: false 192 | TableType: EXTERNAL_TABLE 193 | 194 | NLBTLSVersion30days: 195 | Type: AWS::Athena::NamedQuery 196 | Properties: 197 | Database: 198 | Ref: dbelblogsathenaelblogstack637ED423 199 | QueryString: !Sub |- 200 | SELECT elb, tls_protocol_version, ROUND((COUNT(tls_protocol_version)* 100.0 / (SELECT COUNT(*) FROM "tb_nlb_logs_${LBLogsBucketName}" WHERE tls_protocol_version != '-')),2) AS percentage, COUNT() AS requests 201 | FROM "tb_nlb_logs_${LBLogsBucketName}" 202 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 203 | AND NOT tls_protocol_version = '-' 204 | GROUP BY elb, tls_protocol_version 205 | ORDER BY percentage DESC 206 | Description: NLB - TLS Version - 30 days 207 | Name: !Sub NLB - TLS Version - 30 days - ${LBLogsBucketName} 208 | WorkGroup: !Ref wgelblogsathenaelblogstack 209 | 210 | NLBTLSCiphersuites30days: 211 | Type: AWS::Athena::NamedQuery 212 | Properties: 213 | Database: 214 | Ref: dbelblogsathenaelblogstack637ED423 215 | QueryString: !Sub |- 216 | SELECT elb, tls_cipher, ROUND((COUNT(tls_cipher)* 100.0 / (SELECT COUNT(*) FROM "tb_nlb_logs_${LBLogsBucketName}" WHERE tls_cipher != '-')),2) AS percentage, COUNT() AS requests 217 | FROM "tb_nlb_logs_${LBLogsBucketName}" 218 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 219 | AND NOT tls_cipher = '-' 220 | GROUP BY elb, tls_cipher 221 | ORDER BY percentage DESC 222 | Description: NLB - TLS Ciphersuites - 30 days 223 | Name: !Sub NLB - TLS Ciphersuites - 30 days - ${LBLogsBucketName} 224 | WorkGroup: !Ref wgelblogsathenaelblogstack 225 | 226 | NLBTLSVersionandCiphersuitescombined30days: 227 | Type: AWS::Athena::NamedQuery 228 | Properties: 229 | Database: 230 | Ref: dbelblogsathenaelblogstack637ED423 231 | QueryString: !Sub |- 232 | SELECT DISTINCT elb, tls_cipher, tls_protocol_version, count(tls_cipher) AS requests 233 | FROM "tb_nlb_logs_${LBLogsBucketName}" 234 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 235 | AND NOT tls_protocol_version = '-' 236 | GROUP BY elb, tls_cipher,tls_protocol_version 237 | ORDER BY requests DESC 238 | Description: NLB - TLS Version and Ciphersuites combined - 30 days 239 | Name: !Sub NLB - TLS Version and Ciphersuites combined - 30 days - ${LBLogsBucketName} 240 | WorkGroup: !Ref wgelblogsathenaelblogstack 241 | 242 | NLBTop10TLS10talkers30days: 243 | Type: AWS::Athena::NamedQuery 244 | Properties: 245 | Database: 246 | Ref: dbelblogsathenaelblogstack637ED423 247 | QueryString: !Sub |- 248 | SELECT elb, client_ip, COUNT(*) as requests 249 | FROM "tb_nlb_logs_${LBLogsBucketName}" 250 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 251 | AND tls_protocol_version = 'tlsv1' 252 | GROUP BY elb, client_ip 253 | ORDER BY requests DESC 254 | LIMIT 10 255 | Description: NLB - Top 10 TLS 1.0 talkers - 30 days 256 | Name: !Sub NLB - Top 10 TLS 1.0 talkers - 30 days - ${LBLogsBucketName} 257 | WorkGroup: !Ref wgelblogsathenaelblogstack 258 | 259 | NLBTop10talkers30days: 260 | Type: AWS::Athena::NamedQuery 261 | Properties: 262 | Database: 263 | Ref: dbelblogsathenaelblogstack637ED423 264 | QueryString: !Sub |- 265 | SELECT elb, client_ip, COUNT(*) as requests 266 | FROM "tb_nlb_logs_${LBLogsBucketName}" 267 | WHERE from_iso8601_timestamp(time) > current_timestamp - interval '30' day 268 | GROUP BY elb, client_ip 269 | ORDER BY requests DESC 270 | LIMIT 10 271 | Description: NLB - Top 10 talkers - 30 days 272 | Name: !Sub NLB - Top 10 talkers - 30 days - ${LBLogsBucketName} 273 | WorkGroup: !Ref wgelblogsathenaelblogstack -------------------------------------------------------------------------------- /network-load-balancer-copy-utility/README.md: -------------------------------------------------------------------------------- 1 | ## Classic Load Balancer to Network Load Balancer copy utility 2 | 3 | ### Overview: 4 | Customers can utilize this tool to copy the configuration of their existing Classic Load Balancer to create a new Network Load Balancer with the same configuration. Customers can also choose to register their existing backend EC2 instances with the new Network Load Balancer. 5 | 6 | Note: Please make sure that your botocore version number is higher than 1.7.6. 7 | 8 | ### Usage: 9 | ``` 10 | copy_classic_load_balancer.py 11 | --name 12 | --region 13 | [--debug ] 14 | [--register-targets] 15 | [--dry-run] 16 | ``` 17 | 18 | Example 1: Test whether the Load Balancer configuration is supported 19 | ``` 20 | copy_classic_load_balancer.py --name my-load-balancer --region us-west-2 --dry-run 21 | ``` 22 | 23 | Example 2: Create an Network Load Balancer based on the specified Classic Load Balancer but do not register the instances as targets 24 | ``` 25 | copy_classic_load_balancer.py --name my-load-balancer --region us-west-2 26 | ``` 27 | 28 | Example 3: Create an Network Load Balancer based on the specified Classic Load Balancer and register the instances as targets 29 | ``` 30 | copy_classic_load_balancer.py --name my-load-balancer --region us-west-2 --register-targets 31 | ``` 32 | 33 | ### Unsupported Configurations: 34 | 1. A Classic Load Balancer has HTTP, HTTPS or SSL listeners 35 | 2. A Classic Load Balancer is in EC2-Classic 36 | 3. A Classic Load Balancer has been configured with an idle timeout that is longer than 350 seconds. 37 | 4. A Classic Load Balancer has more than 200 unique backend ports 38 | 5. A Classic Load Balancer has more than 10 listeners 39 | 40 | 41 | ### Addition considerations and best practices: 42 | 1. You cannot assign Elastic IP addresses or change their allocation to a Network Load Balancer after the creation step has completed successfully. 43 | 2. Network Load Balancer only accept the same value for healthy and unhealthy threshold and this utility tool set this value to the healthy threshold of Classic Load Balancer. 44 | 3. Network Load Balancer only supports a 10 second, or a 30 second health check interval 45 | 4. This tool will only set the health check matching HttpCode to 200-399. If you want to further customize the HTTP response code that is considered as healthy you will need to change it via the AWS console or CLI after the Network Load Balancer is created with this tool. 46 | 5. If you are using an Auto Scaling Group, you will have to manually register the Auto Scaling group with the appropriate target groups. 47 | 6. If you are utilizing Amazon EC2 Container Service (ECS) you will need to configure your service to run behind your Network Load Balancer. 48 | 7. We recommend testing your application on the Network Load Balancer before migrating your traffic. Amazon Route 53 weighted resource record sets let you associate multiple resources with a single DNS name. Using these weighted resource record sets, you can gradually shift your traffic from your Classic Load Balancer to your new Network Load Balancer after testing is complete. For more information about weighted routing please see: 49 | To learn how to create resource records in Route 53 please see: http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html#routing-policy-weighted 50 | For more information please see the Network Load Balancer Documentation: https://docs.aws.amazon.com/elasticloadbalancing/latest/network/introduction.html 51 | 52 | ### License 53 | The Classic Load Balancer to Network Load Balancer copy utility is licensed under the Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0 54 | 55 | 56 | -------------------------------------------------------------------------------- /proprot/README.md: -------------------------------------------------------------------------------- 1 | # ProProt - Proxy Protocol v2 implementation Java library 2 | 3 | ## Overview: 4 | ProProt is a library to parse and generate network connection headers based on the Proxy Protocol version 2 (PPv2): https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt. 5 | The library also supports Proxy Protocol v2 extensions with custom TLVs, such as that from VPC Endpoint Services: http://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol. 6 | 7 | ## Usage: 8 | 9 | Example 1: Reading 10 | ```java 11 | InputStream in = ... 12 | ProxyProtocol protocol = new ProxyProtocol(); 13 | Header header = protocol.read(in); 14 | ``` 15 | 16 | Example 2: Writing 17 | ```java 18 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 19 | final Header header = new Header(); 20 | header.setCommand(Command.LOCAL); 21 | header.setAddressFamily(AddressFamily.AF_UNSPEC); 22 | header.setTransportProtocol(TransportProtocol.UNSPEC); 23 | 24 | TlvRaw tlv = new TlvRaw(); 25 | tlv.setType(0xF0); 26 | tlv.setValue(new byte[] {1, 2, 3, 4, 5, 6, 7, 8}); 27 | header.addTlv(tlv); 28 | ProxyProtocol protocol = new ProxyProtocol(); 29 | protocol.write(header, out); 30 | ``` 31 | 32 | Example 3: Parsing input from AWS Network Load Balancer with TLV type 0xEA. See [Compatibility_AwsNetworkLoadBalancerTest](/proprot/tst/com/amazonaws/proprot/Compatibility_AwsNetworkLoadBalancerTest.java). 33 | 34 | Unless explicitly specified all the values used throughout the library can not be null. 35 | 36 | The library allows to extend the protocol with custom TLVs. You can use either the predefined types 37 | TlvRaw and TlvSubTypeRaw or define your own. 38 | 39 | ## Installation 40 | 41 | ### Prerequisites 42 | 43 | - Java 8 44 | 45 | ### Install Package 46 | 47 | Choose your installation method - Maven or Jar file. 48 | 49 | #### via Maven 50 | Add ProProt as a dependency on your pom.xml: 51 | ```xml 52 | 53 | com.amazonaws.proprot 54 | proprot 55 | 1.0 56 | 57 | ``` 58 | 59 | #### via jar file 60 | 61 | You can drop the jar file of the library: [proprot-1.0.jar](/proprot/latest-jar/proprot-1.0.jar). 62 | 63 | ### Dependencies 64 | 65 | - [GoogleGuava](https://mvnrepository.com/artifact/com.google.guava/guava) 66 | 67 | ### Addition considerations and best practices: 68 | 1. ProProt validates the header data consistency and integrity against random changes. 69 | 2. Neither Proxy Protocol nor ProProt's implementation provides header signature nor cryptographically strong integrity check. 70 | They assume that the Proxy Protocol header is generated by trusted sources and can not be maliciously tampered during transmission. 71 | 3. If needed, users can extend the protocol with custom TLVs supporting stronger header validation. 72 | 4. This library is only for Proxy Protocol version 2. It will not work with Proxy Protocol version 1. 73 | 5. If the incoming address family is specified, then addresses must also be specified. 74 | 6. If the incoming header command is LOCAL, we validate the address family with the provided addresses, and then discard them. 75 | 7. Any security concerns or problems will be announced through this README. 76 | 77 | 78 | ### License 79 | ProProt is licensed under the Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0 . 80 | 81 | -------------------------------------------------------------------------------- /proprot/latest-jar/proprot-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/proprot/latest-jar/proprot-1.0.jar -------------------------------------------------------------------------------- /proprot/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.amazonaws.proprot 5 | proprot 6 | 1.0 7 | jar 8 | 9 | ProProt 10 | Java library for parsing and generating Proxy Protocol V2 headers. 11 | https://github.com/aws/elastic-load-balancing-tools/tree/master/proprot 12 | 13 | 14 | src 15 | 16 | 17 | maven-compiler-plugin 18 | 3.5.1 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-source-plugin 28 | 3.0.1 29 | 30 | -Xdoclint:none 31 | 32 | 33 | 34 | attach-sources 35 | 36 | jar 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.apache.maven.plugins 44 | maven-javadoc-plugin 45 | 2.10.4 46 | 47 | -Xdoclint:none 48 | 49 | 50 | 51 | attach-javadocs 52 | 53 | jar 54 | 55 | 56 | 57 | 58 | 59 | 60 | org.apache.maven.plugins 61 | maven-gpg-plugin 62 | 1.5 63 | 64 | 65 | sign-artifacts 66 | verify 67 | 68 | sign 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | https://github.com/aws/elastic-load-balancing-tools/tree/master/proprot 79 | 80 | 81 | 82 | 83 | com.google.guava 84 | guava 85 | 32.0.1 86 | 87 | 88 | 89 | 90 | 1.8 91 | 1.8 92 | UTF-8 93 | 94 | 95 | 96 | 97 | The Apache License, Version 2.0 98 | http://www.apache.org/licenses/LICENSE-2.0.txt 99 | 100 | 101 | 102 | 103 | 104 | amazonwebservices 105 | Amazon Web Services 106 | https://aws.amazon.com 107 | 108 | developer 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/CRC32CInputStream.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.EOFException; 15 | import java.io.IOException; 16 | import java.io.InputStream; 17 | 18 | import com.google.common.hash.Hasher; 19 | import com.google.common.hash.Hashing; 20 | import com.google.common.primitives.Ints; 21 | 22 | /** 23 | * Calculates the stream checksum while allowing to read the expected checksum value from 24 | * the stream interpreting it as zero for the purposes of checksum calculation. 25 | */ 26 | class CRC32CInputStream extends InputStream { 27 | // XXX with the move to Java9 switch to http://download.java.net/java/jdk9/docs/api/java/util/zip/CRC32C.html? 28 | private final Hasher hasher; 29 | private final InputStream in; 30 | 31 | public CRC32CInputStream(InputStream in, boolean calculateChecksum) { 32 | this.in = in; 33 | this.hasher = calculateChecksum ? Hashing.crc32c().newHasher() : NullHasher.INSTANCE; 34 | } 35 | 36 | @Override 37 | public int read() throws IOException { 38 | int b = in.read(); 39 | if (b != -1) { 40 | hasher.putByte((byte) b); 41 | } 42 | return b; 43 | } 44 | 45 | @Override 46 | public int read(byte[] b, int off, int len) throws IOException { 47 | int result = in.read(b, off, len); 48 | if (result != -1) { 49 | hasher.putBytes(b, off, result); 50 | } 51 | return result; 52 | } 53 | 54 | public int readChecksum() throws IOException { 55 | int b1 = in.read(); 56 | int b2 = in.read(); 57 | int b3 = in.read(); 58 | int b4 = in.read(); 59 | if ((b1 | b2 | b3 | b4) < 0) { 60 | throw new EOFException(); 61 | } 62 | 63 | hasher.putBytes(Util.INT0); 64 | return Ints.fromBytes((byte) b1, (byte) b2, (byte) b3, (byte) b4); 65 | } 66 | 67 | public int getChecksum() { 68 | return hasher.hash().asInt(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/CRC32COutputStream.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.IOException; 16 | import java.io.OutputStream; 17 | 18 | import com.google.common.hash.Hasher; 19 | import com.google.common.hash.Hashing; 20 | import com.google.common.primitives.Ints; 21 | 22 | /** 23 | * Calculation of the CRC32c checksum is implemented as output stream, so it can be used 24 | * with {@link ByteArrayOutputStream#writeTo(OutputStream)}. 25 | * Assumes the checksum value comes right after the data being checksummed and includes 26 | * the zero value checksum into the checksum calculation. 27 | */ 28 | class CRC32COutputStream extends OutputStream { 29 | private final OutputStream out; 30 | private final Hasher hasher; 31 | 32 | public CRC32COutputStream(OutputStream out, boolean calculateChecksum) { 33 | this.hasher = calculateChecksum ? Hashing.crc32c().newHasher() : NullHasher.INSTANCE; 34 | this.out = out; 35 | } 36 | 37 | @Override 38 | public void write(int b) throws IOException { 39 | hasher.putByte((byte) b); 40 | out.write(b); 41 | } 42 | 43 | @Override 44 | public void write(byte[] b, int off, int len) throws IOException { 45 | hasher.putBytes(b, off, len); 46 | out.write(b, off, len); 47 | } 48 | 49 | @Override 50 | public void write(byte[] b) throws IOException { 51 | hasher.putBytes(b); 52 | out.write(b); 53 | } 54 | 55 | /** 56 | * Writes the checksum calculated on the data so far plus zero checksum value to the 57 | * wrapped output stream. 58 | */ 59 | public void writeChecksum() throws IOException { 60 | hasher.putBytes(Util.INT0); 61 | out.write(Ints.toByteArray(hasher.hash().asInt())); 62 | } 63 | 64 | @Override 65 | public void close() throws IOException { 66 | out.close(); 67 | } 68 | 69 | @Override 70 | public void flush() throws IOException { 71 | out.flush(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/Generator.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static com.amazonaws.proprot.Util.toHex; 15 | import static com.amazonaws.proprot.Util.writeShort; 16 | 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.DataOutputStream; 19 | import java.io.IOException; 20 | import java.io.OutputStream; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.Arrays; 23 | import java.util.HashMap; 24 | import java.util.Map; 25 | import java.util.Optional; 26 | 27 | import com.amazonaws.proprot.Header.SslFlags; 28 | import com.amazonaws.proprot.ProxyProtocolSpec.AddressFamily; 29 | 30 | /** 31 | * Generates Proxy Protocol v2 header. 32 | * Is not thread-safe. 33 | * @see ProxyProtocol#read(java.io.InputStream) 34 | */ 35 | class Generator { 36 | private static final int SIZE_OF_HEADER_SIZE_FIELD = Short.BYTES; 37 | 38 | private final Map> adapters = new HashMap<>(); 39 | 40 | /** 41 | * Is used to convert a value to byte[] before writing it out in order to calculate 42 | * its length because length is written before the value. 43 | */ 44 | private final ByteArrayOutputStream valueBuf = new ByteArrayOutputStream(30); 45 | private final DataOutputStream valueOut = new DataOutputStream(valueBuf); 46 | private Header header; 47 | private boolean enforceChecksum; 48 | private Optional enforcedSize = Optional.empty(); 49 | 50 | public void write(Header header, OutputStream outputStream) throws IOException { 51 | this.header = header; 52 | header.validate(); 53 | 54 | // code is ugly because we need to conditionally calculate the checksum, 55 | // backtrack to include the size of the header and the size of the PP2_TYPE_SSL TLV 56 | 57 | CRC32COutputStream out = new CRC32COutputStream(outputStream, enforceChecksum); 58 | ByteArrayOutputStream mainBuf = new ByteArrayOutputStream( 59 | header.getAddressFamily().getAddressSize() * 2 + 100); 60 | 61 | // the fixed-size part of the header before the header size field 62 | writeFixedHeader(mainBuf); 63 | int writtenSize = mainBuf.size(); 64 | mainBuf.writeTo(out); 65 | mainBuf.reset(); 66 | 67 | // the size field should go after the fixed size part 68 | // generate the rest of the header in memory, so we can calculate the size 69 | 70 | writeAddresses(mainBuf); 71 | writeTlvs(mainBuf); 72 | maybeWriteSsl(header, mainBuf); 73 | writtenSize += mainBuf.size(); 74 | maybePadHeader(writtenSize + SIZE_OF_HEADER_SIZE_FIELD + getCrcTlvSize(), mainBuf); 75 | 76 | if (enforceChecksum) { 77 | writeTlvStart(ProxyProtocolSpec.PP2_TYPE_CRC32C, getCrcValueSize(), mainBuf); 78 | } 79 | 80 | // flush the size field 81 | int headerSize = getHeaderSize(mainBuf); 82 | writeShort(headerSize, out); 83 | 84 | // flush mainBuf 85 | mainBuf.writeTo(out); 86 | 87 | // generate and write the checksum 88 | if (enforceChecksum) { 89 | out.writeChecksum(); 90 | } 91 | 92 | // keep static code analysis happy 93 | out.close(); 94 | mainBuf.close(); 95 | } 96 | 97 | /** 98 | * Writes the fixed part of the header up to but not including the header size field. 99 | */ 100 | private void writeFixedHeader(ByteArrayOutputStream out) throws IOException { 101 | out.write(ProxyProtocolSpec.PREFIX); 102 | assert out.size() == 12; 103 | 104 | writeCommand(out); 105 | assert out.size() == 13; 106 | 107 | writeAddressFamilyAndTransportProtocol(out); 108 | assert out.size() == 14; 109 | } 110 | 111 | private void writeCommand(OutputStream out) throws IOException { 112 | out.write(0x20 | header.getCommand().getCode()); 113 | } 114 | 115 | private void writeAddresses(OutputStream out) throws IOException { 116 | AddressFamily af = header.getAddressFamily(); 117 | if (af.equals(AddressFamily.AF_INET) || 118 | af.equals(AddressFamily.AF_INET6)) { 119 | out.write(header.getSrcAddress()); 120 | out.write(header.getDstAddress()); 121 | writeShort(header.getSrcPort(), out); 122 | writeShort(header.getDstPort(), out); 123 | } else if (af.equals(AddressFamily.AF_UNIX)) { 124 | int addressSize = AddressFamily.AF_UNIX.getAddressSize(); 125 | out.write(Arrays.copyOf(header.getSrcAddress(), addressSize)); 126 | out.write(Arrays.copyOf(header.getDstAddress(), addressSize)); 127 | } else { 128 | assert af.equals(AddressFamily.AF_UNSPEC); 129 | } 130 | } 131 | 132 | private void writeTlvs(OutputStream out) throws IOException { 133 | maybeWriteByteTVL(ProxyProtocolSpec.PP2_TYPE_ALPN, header.getAlpn(), out); 134 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_TYPE_AUTHORITY, header.getAuthority(), out); 135 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_TYPE_NETNS, header.getNetNS(), out); 136 | 137 | for (Tlv tlv : header.getTlvs()) { 138 | assert valueBuf.size() == 0; 139 | 140 | TlvAdapter adapter = getAdapter(tlv); 141 | adapter.writeValue(tlv, valueOut); 142 | writeTLVFromValueBuf(tlv.getType(), out); 143 | } 144 | } 145 | 146 | private void maybeWriteSsl(Header header, OutputStream out) throws IOException { 147 | if (header.getSslFlags().isPresent()) { 148 | SslFlags flags = header.getSslFlags().get(); 149 | 150 | ByteArrayOutputStream sslBuf = writeSslTlvs(); 151 | // length 152 | int size = sslBuf.size() + Byte.BYTES + Integer.BYTES; 153 | writeTlvStart(ProxyProtocolSpec.PP2_TYPE_SSL, size, out); 154 | // client 155 | out.write(flags.getClient()); 156 | // verify 157 | out.write(flags.isClientVerifiedCert() ? Util.INT0 : Util.INT1); 158 | 159 | sslBuf.writeTo(out); 160 | 161 | // to keep static code analysis happy 162 | sslBuf.close(); 163 | } 164 | } 165 | 166 | private ByteArrayOutputStream writeSslTlvs() throws IOException { 167 | ByteArrayOutputStream sslBuf = new ByteArrayOutputStream(20); 168 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_SUBTYPE_SSL_VERSION, header.getSslVersion(), sslBuf); 169 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_SUBTYPE_SSL_CN, header.getSslCommonName(), sslBuf); 170 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_SUBTYPE_SSL_CIPHER, header.getSslCipher(), sslBuf); 171 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_SUBTYPE_SSL_SIG_ALG, header.getSslSigAlg(), sslBuf); 172 | maybeWriteStrTVL(ProxyProtocolSpec.PP2_SUBTYPE_SSL_KEY_ALG, header.getSslKeyAlg(), sslBuf); 173 | return sslBuf; 174 | } 175 | 176 | /** 177 | * Should be called last or before last checksum TLV. 178 | */ 179 | void maybePadHeader(int knownSize, OutputStream out) throws IOException { 180 | if (!enforcedSize.isPresent()) { 181 | return; 182 | } 183 | int targetSize = enforcedSize.get(); 184 | if (knownSize == targetSize) { 185 | // nothing to do 186 | return; 187 | } 188 | if (knownSize > targetSize) { 189 | throw new InvalidHeaderException("Header size " + knownSize 190 | + " can not be larger than the specified limit " + targetSize); 191 | } 192 | 193 | int remainingSize = targetSize - knownSize; 194 | if (remainingSize == 1 || remainingSize == 2) { 195 | throw new InvalidHeaderException("Due to Proxy Protocol limitation can not pad header " 196 | + "of size " + knownSize + " by 1 or 2 bytes to the specified limit " 197 | + targetSize); 198 | } else { 199 | int padSize = remainingSize - getTlvStartSize(); 200 | padHeader(padSize, out); 201 | } 202 | } 203 | 204 | private void padHeader(int padSize, OutputStream out) throws IOException { 205 | for (int i = 0; i < padSize; i++) { 206 | valueBuf.write(0); 207 | } 208 | writeTLVFromValueBuf(ProxyProtocolSpec.PP2_TYPE_NOOP, out); 209 | } 210 | 211 | private void maybeWriteStrTVL(int type, Optional data, OutputStream out) 212 | throws IOException { 213 | if (data.isPresent()) { 214 | assert valueBuf.size() == 0; 215 | valueBuf.write(data.get().getBytes(StandardCharsets.UTF_8)); 216 | writeTLVFromValueBuf(type, out); 217 | } 218 | } 219 | 220 | private void maybeWriteByteTVL(int type, Optional data, OutputStream out) 221 | throws IOException { 222 | if (data.isPresent()) { 223 | assert valueBuf.size() == 0; 224 | valueBuf.write(data.get()); 225 | writeTLVFromValueBuf(type, out); 226 | } 227 | } 228 | 229 | private void writeTLVFromValueBuf(int type, OutputStream out) throws IOException { 230 | writeTlvStart(type, valueBuf.size(), out); 231 | valueBuf.writeTo(out); 232 | valueBuf.reset(); 233 | } 234 | 235 | private void writeTlvStart(int type, int size, OutputStream out) throws IOException { 236 | out.write(type); 237 | writeShort(size, out); 238 | } 239 | 240 | TlvAdapter getAdapter(Tlv tlv) { 241 | int type = tlv.getType(); 242 | if (tlv instanceof TlvRaw) { 243 | return new TlvRawAdapter(type); 244 | } else if (adapters.containsKey(type)) { 245 | return adapters.get(type); 246 | } else { 247 | throw new IllegalStateException( 248 | "Unable to find adapter for " + tlv + " of type " + toHex(type)); 249 | } 250 | } 251 | 252 | private void writeAddressFamilyAndTransportProtocol(OutputStream out) throws IOException { 253 | out.write(ProxyProtocolSpec.pack( 254 | header.getAddressFamily(), header.getTransportProtocol())); 255 | } 256 | 257 | private int getHeaderSize(ByteArrayOutputStream mainBuf) { 258 | if (enforceChecksum) { 259 | // only CRC value is left not in mainBuf 260 | return mainBuf.size() + getCrcValueSize(); 261 | } else { 262 | return mainBuf.size(); 263 | } 264 | } 265 | 266 | private int getCrcValueSize() { 267 | return Integer.BYTES; 268 | } 269 | 270 | private int getCrcTlvSize() { 271 | if (enforceChecksum) { 272 | return getTlvStartSize() + getCrcValueSize(); 273 | } else { 274 | return 0; 275 | } 276 | } 277 | 278 | private int getTlvStartSize() { 279 | return Byte.BYTES + Short.BYTES; 280 | } 281 | 282 | public Map> getAdapters() { 283 | return adapters; 284 | } 285 | 286 | public void setEnforceChecksum(boolean enforceChecksum) { 287 | this.enforceChecksum = enforceChecksum; 288 | } 289 | 290 | public void setEnforcedSize(Optional enforcedSize) { 291 | this.enforcedSize = enforcedSize; 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/InputAssist.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.nio.charset.StandardCharsets; 17 | 18 | import com.google.common.io.CountingInputStream; 19 | 20 | /** 21 | * Provides tools helping the ProProt parser and the external TLV adapters to parse Proxy Protocol Header. 22 | * The provided methods reading from the input data stream validate that stream is not read beyond the 23 | * header and that stream does not reach a premature end. 24 | * 25 | * @see ProxyProtocolSpec 26 | */ 27 | public class InputAssist { 28 | private final CountingInputStream cin; 29 | private final CRC32CInputStream in; 30 | private int headerSize; 31 | 32 | public InputAssist(InputStream inputStream, boolean enforceChecksum) { 33 | // use MAX_VALUE before we know the actual header size 34 | headerSize = Integer.MAX_VALUE; 35 | 36 | cin = new CountingInputStream(inputStream); 37 | in = new CRC32CInputStream(cin, enforceChecksum); 38 | } 39 | 40 | /** 41 | * Reads the specified number of bytes to a UTF8 string. 42 | */ 43 | public String readString(int length, String label) throws IOException { 44 | byte[] buf = readBytes(length, label); 45 | return new String(buf, StandardCharsets.UTF_8); 46 | } 47 | 48 | public int readByte() throws IOException { 49 | validateHeaderSizeBeforeRead(1); 50 | 51 | int readByte = in.read(); 52 | checkEOF(readByte); 53 | return readByte; 54 | } 55 | 56 | public int readShort() throws IOException { 57 | validateHeaderSizeBeforeRead(2); 58 | 59 | int b1 = in.read(); 60 | int b2 = in.read(); 61 | checkEOF(b1 | b2); 62 | return (b1 << 8) + b2; 63 | } 64 | 65 | public int readInt() throws IOException { 66 | validateHeaderSizeBeforeRead(4); 67 | 68 | int b1 = in.read(); 69 | int b2 = in.read(); 70 | int b3 = in.read(); 71 | int b4 = in.read(); 72 | checkEOF(b1 | b2 | b3 | b4); 73 | return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4; 74 | } 75 | 76 | /** 77 | * Same as {@link #readBytesIntoBuf(int, String)} but reads the data into a newly created array 78 | * which is returned. 79 | */ 80 | public byte[] readBytes(int length, String label) throws IOException, InvalidHeaderException { 81 | // to handle zero-length reads, InputStream.read with zero length does not return 0 82 | if (length == 0) { 83 | return new byte[0]; 84 | } 85 | // Experimented with reusing a buffer instead of creating a new one every time, 86 | // but that did not make much difference. 87 | // There was no difference for a header without TLVs and about 13% smaller memory usage 88 | // for the headers with all the known TLVs. That does not seem to be worth the added code 89 | // complexity since this is not a very realistic case. 90 | validateHeaderSizeBeforeRead(length); 91 | 92 | byte[] b = new byte[length]; 93 | int readCount = in.read(b); 94 | checkEOF(readCount); 95 | if (readCount < length) { 96 | throw new InvalidHeaderException("Premature end of the Proxy Protocol prefix data stream " 97 | + "when reading " + label + ". " 98 | + "Read " + readCount + " bytes instead of expected " + length + "."); 99 | } 100 | return b; 101 | } 102 | 103 | /** 104 | * Reads the protocol header size from the input stream. 105 | */ 106 | void readHeaderSize() throws IOException { 107 | headerSize = readShort() + ProxyProtocolSpec.ADD_TO_HEADER_SIZE; 108 | } 109 | 110 | /** 111 | * Throws the EOF exception if the read result is -1. 112 | */ 113 | private void checkEOF(int readResult) { 114 | if (readResult == -1) { 115 | throw throwEOF(cin.getCount()); 116 | } 117 | } 118 | 119 | private InvalidHeaderException throwEOF(long readCount) { 120 | throw new InvalidHeaderException( 121 | "Premature end of the Proxy Protocol prefix data stream after " 122 | + readCount + " bytes"); 123 | } 124 | 125 | void validateHeaderSizeBeforeRead(int readSize) { 126 | long countBeforeRead = getReadCount(); 127 | if (countBeforeRead + readSize > headerSize) { 128 | throw new InvalidHeaderException( 129 | "Proxy Protocol header is longer than its declared size " + headerSize + "."); 130 | } 131 | } 132 | 133 | /** 134 | * The number of bytes read from the provided stream so far. 135 | */ 136 | public long getReadCount() { 137 | return cin.getCount(); 138 | } 139 | 140 | /** 141 | * The position in the stream, 1 less than {@link #getReadCount()}. 142 | */ 143 | public long getReadPos() { 144 | return getReadCount() - 1; 145 | } 146 | 147 | int readChecksum() throws IOException { 148 | return in.readChecksum(); 149 | } 150 | 151 | int getChecksum() { 152 | return in.getChecksum(); 153 | } 154 | 155 | public InputStream getDataInputStream() { 156 | return in; 157 | } 158 | 159 | void setHeaderSize(int headerSize) { 160 | this.headerSize = headerSize; 161 | } 162 | 163 | int getHeaderSize() { 164 | return headerSize; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/InvalidHeaderException.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | /** 15 | * Indicates a problem with parsing or generating the Proxy Protocol header. 16 | */ 17 | public class InvalidHeaderException extends RuntimeException { 18 | public InvalidHeaderException(String message) { 19 | super(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/NullHasher.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.nio.ByteBuffer; 15 | import java.nio.charset.Charset; 16 | 17 | import com.google.common.hash.Funnel; 18 | import com.google.common.hash.HashCode; 19 | import com.google.common.hash.Hasher; 20 | 21 | class NullHasher implements Hasher { 22 | private static final HashCode HASH_CODE = HashCode.fromInt(0); 23 | public static final Hasher INSTANCE = new NullHasher(); 24 | 25 | @Override 26 | public Hasher putByte(byte b) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public Hasher putBytes(byte[] bytes) { 32 | return null; 33 | } 34 | 35 | public Hasher putBytes(ByteBuffer bytes) { 36 | return null; 37 | } 38 | 39 | @Override 40 | public Hasher putBytes(byte[] bytes, int off, int len) { 41 | return null; 42 | } 43 | 44 | @Override 45 | public Hasher putShort(short s) { 46 | return null; 47 | } 48 | 49 | @Override 50 | public Hasher putInt(int i) { 51 | return null; 52 | } 53 | 54 | @Override 55 | public Hasher putLong(long l) { 56 | return null; 57 | } 58 | 59 | @Override 60 | public Hasher putFloat(float f) { 61 | return null; 62 | } 63 | 64 | @Override 65 | public Hasher putDouble(double d) { 66 | return null; 67 | } 68 | 69 | @Override 70 | public Hasher putBoolean(boolean b) { 71 | return null; 72 | } 73 | 74 | @Override 75 | public Hasher putChar(char c) { 76 | return null; 77 | } 78 | 79 | @Override 80 | public Hasher putUnencodedChars(CharSequence charSequence) { 81 | return null; 82 | } 83 | 84 | @Override 85 | public Hasher putString(CharSequence charSequence, Charset charset) { 86 | return null; 87 | } 88 | 89 | @Override 90 | public Hasher putObject(T instance, Funnel funnel) { 91 | return null; 92 | } 93 | 94 | @Override 95 | public HashCode hash() { 96 | return HASH_CODE; 97 | } 98 | } -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/ProxyProtocol.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static com.amazonaws.proprot.Util.toHex; 15 | 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.io.OutputStream; 19 | import java.util.Collection; 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | import java.util.Optional; 23 | 24 | import com.google.common.base.Preconditions; 25 | 26 | /** 27 | * Marshalls and unmarshalls the Proxy Protocol header. 28 | * The facade of the library. Is thread-safe once configured. 29 | */ 30 | public class ProxyProtocol { 31 | private boolean readUnknownTLVs = true; 32 | private boolean enforceChecksum = true; 33 | private Optional enforcedSize = Optional.empty(); 34 | 35 | private final Map> adapters = new HashMap<>(); 36 | 37 | /** 38 | * Reads the protocol header. 39 | * On successful completion the input stream is positioned on the first byte after 40 | * the Proxy Protocol header data. That's the first byte of the original connection. 41 | */ 42 | public Header read(InputStream in) throws IOException, InvalidHeaderException { 43 | Parser parser = new Parser(); 44 | parser.setReadUnknownTLVs(isReadUnknownTLVs()); 45 | parser.setEnforceChecksum(isEnforceChecksum()); 46 | parser.getAdapters().putAll(getAdapters()); 47 | return parser.read(in); 48 | } 49 | 50 | /** 51 | * Writes the protocol header. 52 | */ 53 | public void write(Header header, OutputStream out) throws IOException, InvalidHeaderException { 54 | Generator generator = new Generator(); 55 | generator.setEnforceChecksum(isEnforceChecksum()); 56 | generator.setEnforcedSize(getEnforcedSize()); 57 | generator.getAdapters().putAll(getAdapters()); 58 | generator.write(header, out); 59 | } 60 | 61 | /** 62 | *

Indicates whether {@link #read(InputStream)} returns the TLVs this object does not have 63 | * adapters for. If true the unrecognized TLVs are returned as {@link TlvRaw}s. 64 | *

65 | *

By default returns true.

66 | */ 67 | public boolean isReadUnknownTLVs() { 68 | return readUnknownTLVs; 69 | } 70 | 71 | /** 72 | * @see #isReadUnknownTLVs() 73 | */ 74 | public void setReadUnknownTLVs(boolean readUnknownTLVs) { 75 | this.readUnknownTLVs = readUnknownTLVs; 76 | } 77 | 78 | /** 79 | *

If true, enforce the checksum when reading and writing the protocol header. 80 | * When reading, calculate the checksum and throw {@link InvalidHeaderException} if 81 | * the checksum does not match the checksum specified in the header or the header does not 82 | * include the checksum. Generate the checksum when writing.

83 | * 84 | *

If false, the checksum is ignored when reading and is not generated when 85 | * writing. 86 | *

87 | * 88 | *

The checksum is not exposed as a TLV object even though according to the protocol 89 | * specification it is stored as a TLV. 90 | *

91 | * 92 | *

By default returns true.

93 | * 94 | *

Checksum processing approximately doubles processing time of a header.

95 | * 96 | */ 97 | public boolean isEnforceChecksum() { 98 | return enforceChecksum; 99 | } 100 | 101 | public void setEnforceChecksum(boolean enforceChecksum) { 102 | this.enforceChecksum = enforceChecksum; 103 | } 104 | 105 | /** 106 | * If specified, the class generates Proxy Protocol headers of the specified size if necessary 107 | * padding the header with the {@link ProxyProtocolSpec#PP2_TYPE_NOOP} TLV. 108 | * {@link #write(Header, OutputStream)} throws {@link InvalidHeaderException} if the size of 109 | * the generated header is greater than the specified size. Due to the restriction of the Proxy 110 | * Protocol the exception is also thrown when the generated header is smaller than the 111 | * specified size by 1 or 2 bytes. 112 | * @return by default returns {@link Optional#empty()} 113 | */ 114 | public Optional getEnforcedSize() { 115 | return enforcedSize; 116 | } 117 | 118 | /** 119 | * @see #getEnforcedSize() 120 | */ 121 | public void setEnforcedSize(Optional enforcedSize) { 122 | this.enforcedSize = enforcedSize; 123 | } 124 | 125 | /** 126 | * A map of adapter type to adapter. 127 | */ 128 | public Map> getAdapters() { 129 | validateAdapters(); 130 | return adapters; 131 | } 132 | 133 | public void setAdapters(Collection> adapterColl) { 134 | Preconditions.checkNotNull(adapters); 135 | adapters.clear(); 136 | for (TlvAdapter adapter : adapterColl) { 137 | TlvAdapter oldAdapter = adapters.put(adapter.getType(), adapter); 138 | if (oldAdapter != null) { 139 | throw new IllegalArgumentException("Found two adapters for the same TLV type " 140 | + toHex(adapter.getType()) + ": " + oldAdapter + " and " + adapter); 141 | } 142 | } 143 | validateAdapters(); 144 | } 145 | 146 | private void validateAdapters() { 147 | for (Integer adapterType: adapters.keySet()) { 148 | if (ProxyProtocolSpec.STANDARD_TLV_TYPES.contains(adapterType)) { 149 | throw new IllegalArgumentException( 150 | "The TLV type " + toHex(adapterType) + " is handled by the library " 151 | + "and can not be processed by the external adapter " + adapters.get(adapterType)); 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/ProxyProtocolSpec.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static com.amazonaws.proprot.Util.toHex; 15 | 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | import java.util.Set; 19 | 20 | import com.google.common.collect.ImmutableSet; 21 | 22 | /** 23 | * The constants describing the Proxy Protocol. 24 | * Whenever possible the names here correspond to the protocol specification. 25 | * See the protocol specification for more information. 26 | */ 27 | public final class ProxyProtocolSpec { 28 | public static final byte[] PREFIX = {0xD, 0xA, 0xD, 0xA, 0x0, 0xD, 0xA, 0x51, 0x55, 0x49, 0x54, 0x0A}; 29 | 30 | // 13th byte 31 | public static final int PROTOCOL_V2 = 0x2; 32 | 33 | public interface Code { 34 | int getCode(); 35 | } 36 | 37 | public enum Command implements Code { 38 | LOCAL(0x0), PROXY(0x1); 39 | 40 | private static Map valuesByCode = new HashMap<>(); 41 | 42 | private final int code; 43 | 44 | static { 45 | initCodeEnum(values(), valuesByCode); 46 | } 47 | 48 | private Command(int code) { 49 | this.code = code; 50 | } 51 | 52 | public static Command valueOf(Integer code, long pos) { 53 | return valueByCode(code, valuesByCode, pos); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return codeEnumToString(this); 59 | } 60 | 61 | @Override 62 | public int getCode() { 63 | return code; 64 | } 65 | } 66 | 67 | // 14th byte 68 | 69 | public enum AddressFamily implements Code { 70 | AF_UNSPEC(0x0, 0), AF_INET(0x1, 4), AF_INET6(0x2, 16), AF_UNIX(0x3, 108); 71 | 72 | private static Map valuesByCode = new HashMap<>(); 73 | 74 | private final int code; 75 | private final int addressSize; 76 | 77 | static { 78 | initCodeEnum(values(), valuesByCode); 79 | } 80 | 81 | private AddressFamily(int code, int addressSize) { 82 | this.code = code; 83 | this.addressSize = addressSize; 84 | } 85 | 86 | public static AddressFamily valueOf(Integer code, long pos) { 87 | return valueByCode(code, valuesByCode, pos); 88 | } 89 | 90 | @Override 91 | public String toString() { 92 | return codeEnumToString(this); 93 | } 94 | 95 | @Override 96 | public int getCode() { 97 | return code; 98 | } 99 | 100 | /** 101 | * The number of bytes reserved for address of the family. 102 | */ 103 | public int getAddressSize() { 104 | return addressSize; 105 | } 106 | } 107 | 108 | public enum TransportProtocol implements Code { 109 | UNSPEC(0x0), STREAM(0x1), DGRAM(0x2); 110 | 111 | private static Map valuesByCode = new HashMap<>(); 112 | 113 | private final int code; 114 | 115 | static { 116 | initCodeEnum(values(), valuesByCode); 117 | } 118 | 119 | private TransportProtocol(int code) { 120 | this.code = code; 121 | } 122 | 123 | public static TransportProtocol valueOf(Integer code, long pos) { 124 | return valueByCode(code, valuesByCode, pos); 125 | } 126 | 127 | @Override 128 | public String toString() { 129 | return codeEnumToString(this); 130 | } 131 | 132 | @Override 133 | public int getCode() { 134 | return code; 135 | } 136 | } 137 | 138 | /** 139 | * Valid AF/TP combinations. 140 | */ 141 | public static final Set VALID_AF_TP_VALUES = ImmutableSet.of( 142 | // UNSPEC 143 | 0x00, 144 | // TCP over IPv4 145 | 0x11, 146 | // UDP over IPv4 147 | 0x12, 148 | // TCP over IPv6 149 | 0x21, 150 | // UDP over IPv6 151 | 0x22, 152 | // UNIX stream 153 | 0x31, 154 | // UNIX datagram 155 | 0x32); 156 | 157 | // 15th & 16th bytes - address length in bytes 158 | /** 159 | * The number of bytes to add to the value stored in the header size field to calculate the total size of a header. 160 | */ 161 | public static final int ADD_TO_HEADER_SIZE = 16; 162 | 163 | // Value Types 164 | public static final int PP2_TYPE_ALPN = 0x1; 165 | public static final int PP2_TYPE_AUTHORITY = 0x2; 166 | public static final int PP2_TYPE_CRC32C = 0x3; 167 | public static final int PP2_TYPE_NOOP = 0x4; 168 | public static final int PP2_TYPE_SSL = 0x20; 169 | public static final int PP2_SUBTYPE_SSL_VERSION = 0x21; 170 | public static final int PP2_SUBTYPE_SSL_CN = 0x22; 171 | public static final int PP2_SUBTYPE_SSL_CIPHER = 0x23; 172 | public static final int PP2_SUBTYPE_SSL_SIG_ALG = 0x24; 173 | public static final int PP2_SUBTYPE_SSL_KEY_ALG = 0x25; 174 | public static final int PP2_TYPE_NETNS = 0x30; 175 | 176 | public static final int PP2_CLIENT_SSL = 0x01; 177 | public static final int PP2_CLIENT_CERT_CONN = 0x02; 178 | public static final int PP2_CLIENT_CERT_SESS = 0x04; 179 | 180 | public static final Set STANDARD_TLV_TYPES = ImmutableSet.of( 181 | ProxyProtocolSpec.PP2_TYPE_ALPN, 182 | ProxyProtocolSpec.PP2_TYPE_AUTHORITY, 183 | ProxyProtocolSpec.PP2_TYPE_CRC32C, 184 | ProxyProtocolSpec.PP2_TYPE_NOOP, 185 | ProxyProtocolSpec.PP2_TYPE_SSL, 186 | ProxyProtocolSpec.PP2_SUBTYPE_SSL_VERSION, 187 | ProxyProtocolSpec.PP2_SUBTYPE_SSL_CN, 188 | ProxyProtocolSpec.PP2_SUBTYPE_SSL_CIPHER, 189 | ProxyProtocolSpec.PP2_SUBTYPE_SSL_SIG_ALG, 190 | ProxyProtocolSpec.PP2_SUBTYPE_SSL_KEY_ALG, 191 | ProxyProtocolSpec.PP2_TYPE_NETNS); 192 | 193 | 194 | /** 195 | * Packs address family and transport protocol into a single byte as described by the spec. 196 | */ 197 | public static int pack(AddressFamily addressFamily, TransportProtocol transportProtocol) { 198 | return (addressFamily.getCode() << 4) | transportProtocol.getCode(); 199 | } 200 | 201 | 202 | private static & Code> E valueByCode( 203 | Integer code, Map valuesByCode, long pos) { 204 | E value = valuesByCode.get(code); 205 | if (value == null) { 206 | Class enumClass = getEnumClass(valuesByCode); 207 | throw new InvalidHeaderException("Unexpected code " + toHex(code) + " for " 208 | + enumClass.getSimpleName() 209 | + " at byte " + pos); 210 | } else { 211 | return value; 212 | } 213 | } 214 | 215 | /** 216 | * Should be called by the {@link Code} enumerations. 217 | * @param valuesByCode is populated by the method. 218 | */ 219 | static & Code> void initCodeEnum( 220 | E[] values, Map valuesByCode) { 221 | assert valuesByCode.isEmpty(); 222 | for (E value : values) { 223 | int code = value.getCode(); 224 | E oldValue = valuesByCode.put(code, value); 225 | if (oldValue != null) { 226 | Class enumClass = getEnumClass(valuesByCode); 227 | throw new InvalidHeaderException(enumClass.getSimpleName() 228 | + " has multiple constants with the same code " + toHex(code) + " - " 229 | + value.toString() + " and " + oldValue.toString()); 230 | } 231 | } 232 | } 233 | 234 | private static & Code> String codeEnumToString(E value) { 235 | return value.name() + "(" + value.getCode() + ")"; 236 | } 237 | 238 | /** 239 | * Class of the map values. 240 | */ 241 | private static & Code> Class getEnumClass(Map valuesByCode) { 242 | return valuesByCode.values().iterator().next().getDeclaringClass(); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/Scrap.jpage: -------------------------------------------------------------------------------- 1 | int code = 0x2 << 4 | 0x1; 2 | System.out.println(code); 3 | System.out.println((code >> 4) & 0xF); //first 4 | System.out.println(code & 0xF); //second 5 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/Tlv.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | /** 15 | * The protocol Type-Length-Value record. 16 | * Length is not returned because it describes the length of the original encoded data and is not 17 | * interesting. 18 | */ 19 | public interface Tlv { 20 | int getType(); 21 | } 22 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/TlvAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.DataOutputStream; 15 | import java.io.IOException; 16 | 17 | /** 18 | * Writes and reads a TLV. The implementations must be thread-safe. 19 | */ 20 | public interface TlvAdapter { 21 | /** 22 | * Returns the TLV type handled by the adapter. 23 | */ 24 | int getType(); 25 | 26 | /** 27 | * The implementors don't need to validate whether all the available data was read. 28 | * The caller will throw an exception when the number of bytes read from the input 29 | * stream does not equal to the "length" parameter. 30 | * 31 | * @param inputAssist contains the input data stream to read the TLV value from and 32 | * the parsing tools. 33 | * @param length the number of bytes belonging to the TLV in the provided input stream. 34 | */ 35 | T read(InputAssist inputAssist, int length) throws IOException, InvalidHeaderException; 36 | 37 | /** 38 | * Serializes the value of the provided TLV to the output stream. 39 | */ 40 | void writeValue(Tlv tlv, DataOutputStream out) throws IOException, InvalidHeaderException; 41 | } 42 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/TlvRaw.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | /** 15 | * Uninterpreted TLV, represents the TLV contents as a byte array. 16 | */ 17 | public class TlvRaw implements Tlv { 18 | private int type; 19 | private byte[] value; 20 | 21 | @Override 22 | public int getType() { 23 | return type; 24 | } 25 | 26 | public void setType(int type) { 27 | this.type = type; 28 | } 29 | 30 | public byte[] getValue() { 31 | return value; 32 | } 33 | 34 | public void setValue(byte[] value) { 35 | this.value = value; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/TlvRawAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.DataOutputStream; 15 | import java.io.IOException; 16 | 17 | public class TlvRawAdapter implements TlvAdapter { 18 | private final int type; 19 | 20 | public TlvRawAdapter(int type) { 21 | this.type = type; 22 | } 23 | 24 | @Override 25 | public int getType() { 26 | return type; 27 | } 28 | 29 | @Override 30 | public TlvRaw read(InputAssist inputAssist, int length) throws IOException { 31 | TlvRaw tlv = new TlvRaw(); 32 | tlv.setType(type); 33 | tlv.setValue(inputAssist.readBytes(length, "TLV " + type)); 34 | return tlv; 35 | } 36 | 37 | @Override 38 | public void writeValue(Tlv tlv, DataOutputStream out) throws IOException { 39 | out.write(((TlvRaw) tlv).getValue()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/TlvSubTypeRaw.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | 13 | package com.amazonaws.proprot; 14 | 15 | /** 16 | * TlvSubTypeRaw implements a pattern of extending Proxy Protocol with a TLV having a byte-sized subtype. 17 | */ 18 | public class TlvSubTypeRaw implements Tlv { 19 | private int type; 20 | private int subType; 21 | private byte[] value; 22 | 23 | @Override 24 | public int getType() { 25 | return type; 26 | } 27 | 28 | public int getSubType() { 29 | return subType; 30 | } 31 | 32 | public void setType(int type) { 33 | this.type = type; 34 | } 35 | 36 | public void setSubType(int subType) { 37 | this.subType = subType; 38 | } 39 | 40 | public byte[] getValue() { 41 | return value; 42 | } 43 | 44 | public void setValue(byte[] value) { 45 | this.value = value; 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/TlvSubTypeRawAdapter.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | 15 | 16 | import java.io.DataOutputStream; 17 | import java.io.IOException; 18 | import java.util.Arrays; 19 | 20 | public class TlvSubTypeRawAdapter implements TlvAdapter { 21 | private final int type; 22 | 23 | public TlvSubTypeRawAdapter(int type) { 24 | this.type = type; 25 | } 26 | 27 | @Override 28 | public int getType() { 29 | return type; 30 | } 31 | 32 | @Override 33 | public TlvSubTypeRaw read(InputAssist inputAssist, int length) throws IOException { 34 | if (length < 1) { 35 | throw new InvalidHeaderException("Unexpected length " + length + " of the TLV " + type + ". Should be at least 1."); 36 | } 37 | TlvSubTypeRaw tlv = new TlvSubTypeRaw(); 38 | tlv.setType(type); 39 | tlv.setSubType(inputAssist.readByte()); 40 | tlv.setValue(inputAssist.readBytes(length - 1, "TLV " + type)); 41 | return tlv; 42 | } 43 | 44 | @Override 45 | public void writeValue(Tlv tlv, DataOutputStream out) throws IOException { 46 | TlvSubTypeRaw subTypeTlv = (TlvSubTypeRaw) tlv; 47 | out.writeByte(subTypeTlv.getSubType()); 48 | out.write(subTypeTlv.getValue()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /proprot/src/com/amazonaws/proprot/Util.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import java.io.DataOutputStream; 15 | import java.io.IOException; 16 | import java.io.OutputStream; 17 | 18 | 19 | class Util { 20 | public final static byte[] INT0 = new byte[] {0, 0, 0, 0}; 21 | public final static byte[] INT1 = new byte[] {0, 0, 0, 1}; 22 | 23 | public static String toHex(int b) { 24 | return "0x" + Integer.toHexString(b); 25 | } 26 | 27 | 28 | /** 29 | * When we do not want to create {@link DataOutputStream} to write out the data. 30 | */ 31 | public static void writeShort(int v, OutputStream out) throws IOException { 32 | out.write((v >>> 8) & 0xFF); 33 | out.write((v >>> 0) & 0xFF); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/CRC32CInputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.hamcrest.Matchers.greaterThanOrEqualTo; 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertThat; 17 | 18 | import java.io.ByteArrayInputStream; 19 | import java.io.DataInputStream; 20 | import java.io.IOException; 21 | 22 | import org.junit.Test; 23 | 24 | import com.google.common.hash.Hasher; 25 | import com.google.common.hash.Hashing; 26 | 27 | public class CRC32CInputStreamTest { 28 | /** 29 | * Make sure our CRC32C algorithm works as expected. 30 | */ 31 | @Test 32 | public void testCRC32CSamples() throws IOException { 33 | assertCRC32C(0xC1D04330, (byte) 'a'); 34 | assertCRC32C(0x364B3FB7, (byte) 'a', (byte) 'b', (byte) 'c'); 35 | assertCRC32C(0xc1d04330, (byte) 0x61); 36 | 37 | 38 | // samples from https://tools.ietf.org/html/rfc3720#appendix-B.4 , 39 | // reverted because it seems they had wrong endianness according to the 40 | // Guava and JDK9 implementations of CRC32C 41 | assertCRC32C(0x8A9136AA, 42 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 43 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 44 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 45 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00); 46 | assertCRC32C(0x62A8AB43, 47 | (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 48 | (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 49 | (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 50 | (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF); 51 | assertCRC32C(0x46DD794E, 52 | (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, 53 | (byte) 0x08, (byte) 0x09, (byte) 0x0A, (byte) 0x0B, (byte) 0x0C, (byte) 0x0D, (byte) 0x0E, (byte) 0x0F, 54 | (byte) 0x10, (byte) 0x11, (byte) 0x12, (byte) 0x13, (byte) 0x14, (byte) 0x15, (byte) 0x16, (byte) 0x17, 55 | (byte) 0x18, (byte) 0x19, (byte) 0x1A, (byte) 0x1B, (byte) 0x1C, (byte) 0x1D, (byte) 0x1E, (byte) 0x1F); 56 | assertCRC32C(0x113FDB5C, 57 | (byte) 0x1F, (byte) 0x1E, (byte) 0x1D, (byte) 0x1C, (byte) 0x1B, (byte) 0x1A, (byte) 0x19, (byte) 0x18, 58 | (byte) 0x17, (byte) 0x16, (byte) 0x15, (byte) 0x14, (byte) 0x13, (byte) 0x12, (byte) 0x11, (byte) 0x10, 59 | (byte) 0x0F, (byte) 0x0E, (byte) 0x0D, (byte) 0x0C, (byte) 0x0B, (byte) 0x0A, (byte) 0x09, (byte) 0x08, 60 | (byte) 0x07, (byte) 0x06, (byte) 0x05, (byte) 0x04, (byte) 0x03, (byte) 0x02, (byte) 0x01, (byte) 0x00); 61 | assertCRC32C(0xD9963A56, 62 | (byte) 0x01, (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 63 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 64 | (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, 65 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x18, 66 | (byte) 0x28, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 67 | (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00); 68 | } 69 | 70 | @Test 71 | public void testReadChecksum() throws Exception { 72 | byte[] data = new byte[] {0, 0, 0, 1}; 73 | CRC32CInputStream in1 = new CRC32CInputStream(new ByteArrayInputStream(data), true); 74 | CRC32CInputStream in2 = new CRC32CInputStream(new ByteArrayInputStream(data), true); 75 | DataInputStream din2 = new DataInputStream(in2); 76 | assertEquals(in1.readChecksum(), din2.readInt()); 77 | 78 | CRC32CInputStream in0 = new CRC32CInputStream(new ByteArrayInputStream( 79 | new byte[] {0, 0, 0, 0}), true); 80 | in0.read(new byte[4]); 81 | assertEquals(in0.getChecksum(), in1.getChecksum()); 82 | 83 | in1.close(); 84 | in2.close(); 85 | din2.close(); 86 | in0.close(); 87 | } 88 | 89 | private void assertCRC32C(int crc, byte... data) throws IOException { 90 | byte[] buf = new byte[100]; 91 | assertThat(buf.length, greaterThanOrEqualTo(data.length)); 92 | 93 | CRC32CInputStream in = new CRC32CInputStream(new ByteArrayInputStream(data), true); 94 | assertEquals(data.length, in.read(buf)); 95 | int checksum = in.getChecksum(); 96 | in.close(); 97 | assertEquals("Expected " + Util.toHex(crc) 98 | + ", calculated " + Util.toHex(checksum), crc, checksum); 99 | 100 | // make sure we calculate the same value as the hasher: 101 | { 102 | Hasher hasher = Hashing.crc32c().newHasher(); 103 | hasher.putBytes(data); 104 | assertEquals("Expected " + Util.toHex(crc) 105 | + ", calculated " + Util.toHex(hasher.hash().asInt()), crc, hasher.hash().asInt()); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/CRC32COutputStreamTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertArrayEquals; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.IOException; 19 | import java.util.Arrays; 20 | 21 | import org.junit.Test; 22 | 23 | import com.google.common.primitives.Ints; 24 | 25 | public class CRC32COutputStreamTest { 26 | @Test 27 | public void testCRC32CSamples() throws IOException { 28 | // samples from https://tools.ietf.org/html/rfc7143 ending in byte[] {0, 0, 0, 0} 29 | // the checksum is known for the zero checksum value 30 | assertCRC32C(0x8A9136AA, 31 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 32 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 33 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 34 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00); 35 | assertCRC32C(0xD9963A56, 36 | (byte) 0x01, (byte) 0xC0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 37 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 38 | (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x04, (byte) 0x00, 39 | (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x14, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x18, 40 | (byte) 0x28, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 41 | (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00); 42 | } 43 | 44 | private void assertCRC32C(int crc, byte... data) throws IOException { 45 | ByteArrayOutputStream bout = new ByteArrayOutputStream(); 46 | CRC32COutputStream out = new CRC32COutputStream(bout, true); 47 | int dataLength = data.length - Integer.BYTES; 48 | out.write(data, 0, dataLength); 49 | out.writeChecksum(); 50 | 51 | byte[] buf = bout.toByteArray(); 52 | assertEquals(data.length, buf.length); 53 | assertArrayEquals(Ints.toByteArray(crc), Arrays.copyOfRange(buf, dataLength, data.length)); 54 | 55 | // code coverage, keep static code analysis happy 56 | out.flush(); 57 | out.close(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/Compatibility_AwsNetworkLoadBalancerTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertArrayEquals; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | import java.io.ByteArrayInputStream; 18 | import java.io.IOException; 19 | import java.net.InetAddress; 20 | import java.net.UnknownHostException; 21 | import java.util.Arrays; 22 | 23 | import org.junit.Test; 24 | 25 | import com.amazonaws.proprot.ProxyProtocolSpec.AddressFamily; 26 | import com.amazonaws.proprot.ProxyProtocolSpec.Command; 27 | import com.amazonaws.proprot.ProxyProtocolSpec.TransportProtocol; 28 | import com.google.common.collect.Iterables; 29 | 30 | /** 31 | * The header generated by AWS Network Load Balancer, 32 | * see http://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol . 33 | */ 34 | public class Compatibility_AwsNetworkLoadBalancerTest { 35 | 36 | /** 37 | * A connection done through Private Link/Interface VPC endpoint. 38 | */ 39 | @Test 40 | public void test_PrivateLink() throws IOException { 41 | byte expected_content[] = { 42 | 0x0d, 0x0a, 0x0d, 0x0a, /* Start of Sig */ 43 | 0x00, 0x0d, 0x0a, 0x51, 44 | 0x55, 0x49, 0x54, 0x0a, /* End of Sig */ 45 | 0x21, 0x11, 0x00, 0x54, /* ver_cmd, fam and len */ 46 | (byte) 0xac, 0x1f, 0x07, 0x71, /* Caller src ip */ 47 | (byte) 0xac, 0x1f, 0x0a, 0x1f, /* Endpoint dst ip */ 48 | (byte) 0xc8, (byte) 0xf2, 0x00, 0x50, /* Proxy src port & dst port */ 49 | 0x03, 0x00, 0x04, (byte) 0xe8, /* CRC TLV start */ 50 | (byte) 0xd6, (byte) 0x89, 0x2d, (byte) 0xea, /* CRC TLV cont, VPCE id TLV start */ 51 | 0x00, 0x17, 0x01, 0x76, 52 | 0x70, 0x63, 0x65, 0x2d, 53 | 0x30, 0x38, 0x64, 0x32, 54 | 0x62, 0x66, 0x31, 0x35, 55 | 0x66, 0x61, 0x63, 0x35, 56 | 0x30, 0x30, 0x31, 0x63, 57 | 0x39, 0x04, 0x00, 0x24, /* VPCE id TLV end, NOOP TLV start*/ 58 | 0x00, 0x00, 0x00, 0x00, 59 | 0x00, 0x00, 0x00, 0x00, 60 | 0x00, 0x00, 0x00, 0x00, 61 | 0x00, 0x00, 0x00, 0x00, 62 | 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 66 | 0x00, 0x00, 0x00, 0x00, /* NOOP TLV end */ 67 | }; 68 | 69 | ProxyProtocol protocol = new ProxyProtocol(); 70 | ByteArrayInputStream in = new ByteArrayInputStream(expected_content); 71 | Header header = protocol.read(in); 72 | assertEquals(AddressFamily.AF_INET, header.getAddressFamily()); 73 | assertEquals(TransportProtocol.STREAM, header.getTransportProtocol()); 74 | assertEquals(Command.PROXY, header.getCommand()); 75 | assertEquals("172.31.7.113", getAddressAsStr(header.getSrcAddress())); 76 | assertEquals("172.31.10.31", getAddressAsStr(header.getDstAddress())); 77 | assertEquals(0xC8F2, header.getSrcPort()); 78 | assertEquals(80, header.getDstPort()); 79 | 80 | TlvRaw vpceIdTlv = (TlvRaw) Iterables.getOnlyElement(header.getTlvs()); 81 | // PP2_TYPE_AWS (0xEA) 82 | assertEquals(0xEA, vpceIdTlv.getType()); 83 | byte[] tlvValue = vpceIdTlv.getValue(); 84 | 85 | // PP2_SUBTYPE_AWS_VPCE_ID (0x01) 86 | assertEquals(1, tlvValue[0]); 87 | byte[] vpceIdValue = Arrays.copyOfRange(tlvValue, 1, tlvValue.length); 88 | assertArrayEquals("vpce-08d2bf15fac5001c9".getBytes(), vpceIdValue); 89 | } 90 | 91 | private String getAddressAsStr(byte[] address) throws UnknownHostException { 92 | return InetAddress.getByAddress(address).getHostAddress(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/GeneratorTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.hamcrest.CoreMatchers.instanceOf; 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertSame; 17 | import static org.junit.Assert.assertThat; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.DataOutputStream; 21 | import java.io.IOException; 22 | import java.util.Optional; 23 | 24 | import org.junit.Rule; 25 | import org.junit.Test; 26 | import org.junit.rules.ExpectedException; 27 | 28 | public class GeneratorTest { 29 | private static final int TLV_TYPE = 0xF0; 30 | 31 | @Rule 32 | public ExpectedException thrown = ExpectedException.none(); 33 | 34 | @Test 35 | public void testGetAdapter_found() { 36 | Tlv tlv = new TestTlv(TLV_TYPE); 37 | Generator generator = new Generator(); 38 | TestTlvAdapter adapter = new TestTlvAdapter(); 39 | generator.getAdapters().put(tlv.getType(), adapter); 40 | assertSame(adapter, generator.getAdapter(tlv)); 41 | } 42 | 43 | @Test 44 | public void testGetAdapter_raw() { 45 | TlvRaw tlv = new TlvRaw(); 46 | tlv.setType(0xF0); 47 | tlv.setValue(new byte[] {1, 2, 3}); 48 | 49 | assertThat(new Generator().getAdapter(tlv), instanceOf(TlvRawAdapter.class)); 50 | } 51 | 52 | @Test 53 | public void testGetAdapter_noAdapter() { 54 | thrown.expect(IllegalStateException.class); 55 | thrown.expectMessage("0xf0"); 56 | 57 | Tlv tlv = new TestTlv(0xF0); 58 | new Generator().getAdapter(tlv); 59 | } 60 | 61 | @Test 62 | public void testMaybePadHeader_notPadded() throws IOException { 63 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 64 | new Generator().maybePadHeader(2000, out); 65 | assertEquals(0, out.size()); 66 | } 67 | 68 | @Test 69 | public void testMaybePadHeader_exactSize() throws IOException { 70 | callPadHeader(0); 71 | } 72 | 73 | @Test 74 | public void testMaybePadHeader_exceedsEnforcedSize() throws IOException { 75 | thrown.expect(InvalidHeaderException.class); 76 | callPadHeader(-1); 77 | } 78 | 79 | /** 80 | * Special value - can't pad 1 byte. 81 | */ 82 | @Test 83 | public void testMaybePadHeader_lessThanEnforcedSizeBy1() throws IOException { 84 | thrown.expect(InvalidHeaderException.class); 85 | callPadHeader(1); 86 | } 87 | 88 | /** 89 | * Special value - can't pad 2 bytes. 90 | */ 91 | @Test 92 | public void testMaybePadHeader_lessThenEnforcedSizeBy2() throws IOException { 93 | thrown.expect(InvalidHeaderException.class); 94 | callPadHeader(2); 95 | } 96 | 97 | @Test 98 | public void testMaybePadHeader_lessThenEnforcedSize() throws IOException { 99 | callPadHeader(3); 100 | callPadHeader(4); 101 | callPadHeader(10000); 102 | } 103 | 104 | private void callPadHeader(int enforcedSizeChange) throws IOException { 105 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 106 | Generator generator = new Generator(); 107 | generator.setEnforcedSize(Optional.of(2000 + enforcedSizeChange)); 108 | generator.maybePadHeader(2000, out); 109 | assertEquals(enforcedSizeChange, out.size()); 110 | } 111 | 112 | private class TestTlv implements Tlv { 113 | private final int type; 114 | 115 | public TestTlv(int type) { 116 | this.type = type; 117 | } 118 | 119 | @Override 120 | public int getType() { 121 | return type; 122 | } 123 | } 124 | 125 | private class TestTlvAdapter implements TlvAdapter { 126 | 127 | @Override 128 | public int getType() { 129 | return TLV_TYPE; 130 | } 131 | 132 | @Override 133 | public TestTlv read(InputAssist inputAssist, int length) { 134 | return null; 135 | } 136 | 137 | @Override 138 | public void writeValue(Tlv tlv, DataOutputStream out) {} 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/HeaderTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertFalse; 16 | import static org.junit.Assert.assertSame; 17 | import static org.junit.Assert.assertTrue; 18 | import static org.junit.Assert.fail; 19 | 20 | import java.util.Arrays; 21 | import java.util.Optional; 22 | 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import org.junit.rules.ExpectedException; 26 | 27 | import com.amazonaws.proprot.Header.SslFlags; 28 | import com.amazonaws.proprot.ProxyProtocolSpec.AddressFamily; 29 | import com.amazonaws.proprot.ProxyProtocolSpec.TransportProtocol; 30 | 31 | public class HeaderTest { 32 | @Rule 33 | public ExpectedException thrown = ExpectedException.none(); 34 | 35 | @Test 36 | public void testValidate_defaultValid() { 37 | new Header().validate(); 38 | } 39 | 40 | @Test 41 | public void testVerifyAddressFamilyTransportProtocolCombination_happyPath() { 42 | AddressFamily addressFamily = AddressFamily.AF_INET; 43 | TransportProtocol transportProtocol = TransportProtocol.UNSPEC; 44 | 45 | thrown.expect(InvalidHeaderException.class); 46 | thrown.expectMessage(addressFamily.toString()); 47 | thrown.expectMessage(transportProtocol.toString()); 48 | thrown.expectMessage(Util.toHex(ProxyProtocolSpec.pack(addressFamily, transportProtocol))); 49 | 50 | Header header = new Header(); 51 | header.setAddressFamily(addressFamily); 52 | header.setTransportProtocol(transportProtocol); 53 | header.validate(); 54 | } 55 | 56 | @Test 57 | public void testVerifyAddressSize() { 58 | verifyAddressSize(AddressFamily.AF_INET, TransportProtocol.STREAM); 59 | verifyAddressSize(AddressFamily.AF_INET6, TransportProtocol.STREAM); 60 | verifyAddressSize(AddressFamily.AF_UNIX, TransportProtocol.STREAM); 61 | verifyAddressSize(AddressFamily.AF_UNSPEC, TransportProtocol.UNSPEC); 62 | } 63 | 64 | private void verifyAddressSize(AddressFamily addressFamily, TransportProtocol transportProtocol) { 65 | Header header = new Header(); 66 | header.setAddressFamily(addressFamily); 67 | header.setTransportProtocol(transportProtocol); 68 | 69 | // right size 70 | { 71 | setAddresses(header, addressFamily.getAddressSize()); 72 | header.validate(); 73 | } 74 | 75 | // larger 76 | { 77 | setAddresses(header, addressFamily.getAddressSize() + 1); 78 | try { 79 | header.validate(); 80 | fail(); 81 | } catch (InvalidHeaderException expected) {} 82 | } 83 | 84 | // empty 85 | if (addressFamily.getAddressSize() > 0) { 86 | 87 | setAddresses(header, 0); 88 | try { 89 | header.validate(); 90 | fail(); 91 | } catch (InvalidHeaderException expected) {} 92 | } 93 | } 94 | 95 | private void setAddresses(Header header, int addressSize) { 96 | byte[] address = new byte[addressSize]; 97 | Arrays.fill(address, (byte) 0xF1); 98 | header.setSrcAddress(address); 99 | header.setDstAddress(address); 100 | } 101 | 102 | @Test 103 | public void testSslContainerContains() { 104 | Header header = new Header(); 105 | header.setSslFlags(SslFlags.getOptional(true, false, true, false)); 106 | header.setSslVersion(Optional.of("version 1")); 107 | new Header().validate(); 108 | } 109 | 110 | @Test 111 | public void testSslContainerDoesNotContain() { 112 | thrown.expect(InvalidHeaderException.class); 113 | Header header = new Header(); 114 | header.setSslVersion(Optional.of("version 1")); 115 | header.validate(); 116 | } 117 | 118 | @Test 119 | public void testEqualsHashCode() { 120 | SslFlags flags1 = SslFlags.getOptional(true, true, true, true).get(); 121 | assertEquals(flags1, flags1); 122 | assertFalse(flags1.equals(null)); 123 | assertFalse(flags1.equals(new Object())); 124 | 125 | { 126 | SslFlags flags2 = SslFlags.getOptional(true, true, true, true).get(); 127 | assertEquals(flags1, flags2); 128 | assertEquals(flags1.hashCode(), flags2.hashCode()); 129 | assertEquals(flags1.getClient(), flags2.getClient()); 130 | } 131 | 132 | { 133 | SslFlags flags2 = SslFlags.getOptional(false, false, false, false).get(); 134 | assertFalse(flags1.equals(flags2)); 135 | assertFalse(flags1.hashCode() == flags2.hashCode()); 136 | } 137 | } 138 | 139 | @Test 140 | public void testAddTlv_happyPath() { 141 | Header header = new Header(); 142 | { 143 | TlvRaw tlv = new TlvRaw(); 144 | tlv.setType(0xF3); 145 | header.addTlv(tlv); 146 | } 147 | { 148 | TlvRaw tlv = new TlvRaw(); 149 | tlv.setType(0xF4); 150 | header.addTlv(tlv); 151 | } 152 | { 153 | TlvSubTypeRaw tlv = new TlvSubTypeRaw(); 154 | tlv.setType(0xF4); 155 | tlv.setSubType(0x14); 156 | header.addTlv(tlv); 157 | } 158 | } 159 | 160 | @Test 161 | public void testAddTlv_immutable() { 162 | thrown.expect(UnsupportedOperationException.class); 163 | new Header().getTlvs().add(null); 164 | } 165 | 166 | @Test 167 | public void testAddTlv_knownType() { 168 | thrown.expect(InvalidHeaderException.class); 169 | TlvRaw tlv = new TlvRaw(); 170 | tlv.setType(ProxyProtocolSpec.PP2_TYPE_ALPN); 171 | new Header().addTlv(tlv); 172 | } 173 | 174 | @Test 175 | public void testSslFlags() { 176 | { 177 | SslFlags flags = SslFlags.getOptional(0, false).get(); 178 | assertSame(flags, SslFlags.getOptional(false, false, false, false).get()); 179 | assertFalse(flags.isClientConnectedWithSsl()); 180 | assertFalse(flags.isClientProvidedCertDuringConnection()); 181 | assertFalse(flags.isClientProvidedCertDuringSession()); 182 | assertFalse(flags.isClientVerifiedCert()); 183 | } 184 | { 185 | SslFlags flags = SslFlags.getOptional(0xFF, true).get(); 186 | assertSame(flags, SslFlags.getOptional(true, true, true, true).get()); 187 | assertTrue(flags.isClientConnectedWithSsl()); 188 | assertTrue(flags.isClientProvidedCertDuringConnection()); 189 | assertTrue(flags.isClientProvidedCertDuringSession()); 190 | assertTrue(flags.isClientVerifiedCert()); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/InputAssistTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | import java.io.ByteArrayInputStream; 17 | import java.io.IOException; 18 | 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | import org.junit.rules.ExpectedException; 22 | 23 | public class InputAssistTest { 24 | @Rule 25 | public ExpectedException thrown = ExpectedException.none(); 26 | 27 | @Test 28 | public void testValidateHeaderSizeBeforeRead_happyPath() throws IOException { 29 | int headerSize = 5; 30 | InputAssist assist = newAssist(new byte[] {0, (byte) headerSize}); 31 | assist.readHeaderSize(); 32 | int read = 2; 33 | assist.validateHeaderSizeBeforeRead( 34 | ProxyProtocolSpec.ADD_TO_HEADER_SIZE - read + headerSize); 35 | } 36 | 37 | @Test 38 | public void testValidateHeaderSizeBeforeRead_overHeaderSize() throws IOException { 39 | int headerSize = 5; 40 | thrown.expect(InvalidHeaderException.class); 41 | thrown.expectMessage(Integer.toString(ProxyProtocolSpec.ADD_TO_HEADER_SIZE + headerSize)); 42 | 43 | InputAssist assist = newAssist(new byte[] {0, (byte) headerSize}); 44 | assist.readHeaderSize(); 45 | int read = 2; 46 | assist.validateHeaderSizeBeforeRead( 47 | ProxyProtocolSpec.ADD_TO_HEADER_SIZE - read + headerSize + 1); 48 | } 49 | 50 | @Test 51 | public void testReadShort_happyPath() throws IOException { 52 | InputAssist assist = newAssist(new byte[] {-1, -1}); 53 | assertEquals(0xFFFF, assist.readShort()); 54 | } 55 | 56 | @Test 57 | public void testReadShort_truncated() throws IOException { 58 | thrown.expect(InvalidHeaderException.class); 59 | newAssist(new byte[] {-1}).readShort(); 60 | } 61 | 62 | @Test 63 | public void testReadShort_empty() throws IOException { 64 | thrown.expect(InvalidHeaderException.class); 65 | newAssist(new byte[0]).readShort(); 66 | } 67 | @Test 68 | public void testReadBytes_empty() throws IOException { 69 | newAssist(new byte[0]).readBytes(0, "label"); 70 | } 71 | 72 | 73 | private InputAssist newAssist(byte[] data) { 74 | return new InputAssist(new ByteArrayInputStream(data), false); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/NullHasherTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | import org.junit.Test; 17 | 18 | import com.google.common.hash.Hasher; 19 | 20 | public class NullHasherTest { 21 | @Test 22 | public void testBasics() { 23 | Hasher hasher = NullHasher.INSTANCE; 24 | assertEquals(0, hasher.hash().asInt()); 25 | hasher.putBoolean(false); 26 | hasher.putByte((byte) 3); 27 | hasher.putBytes(new byte[0]); 28 | hasher.putBytes(null, 3, 3); 29 | hasher.putChar('c'); 30 | hasher.putDouble(3.3); 31 | hasher.putFloat(3.4f); 32 | hasher.putInt(7); 33 | hasher.putLong(3); 34 | hasher.putObject(null, null); 35 | hasher.putShort((short) 7); 36 | hasher.putString(null, null); 37 | hasher.putUnencodedChars(null); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/ProxyProtocolSpecTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static java.lang.Integer.toHexString; 15 | import static org.junit.Assert.assertEquals; 16 | 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import org.junit.Rule; 21 | import org.junit.Test; 22 | import org.junit.rules.ExpectedException; 23 | 24 | import com.amazonaws.proprot.ProxyProtocolSpec.Code; 25 | import com.amazonaws.proprot.ProxyProtocolSpec.Command; 26 | 27 | 28 | public class ProxyProtocolSpecTest { 29 | @Rule 30 | public ExpectedException thrown = ExpectedException.none(); 31 | 32 | @Test 33 | public void testValueOf_happyPath() { 34 | assertEquals(Command.PROXY, Command.valueOf(Command.PROXY.getCode(), 37)); 35 | } 36 | 37 | @Test 38 | public void testValidatePrefix_valueOf() { 39 | thrown.expect(InvalidHeaderException.class); 40 | int pos = 37; 41 | thrown.expectMessage(Integer.toString(pos)); 42 | int code = 89; 43 | thrown.expectMessage("0x" + toHexString(code)); 44 | thrown.expectMessage(Command.class.getSimpleName()); 45 | Command.valueOf(code, pos); 46 | } 47 | 48 | @Test 49 | public void testInitCodeEnum_happyPath() { 50 | Map valuesByCode = new HashMap<>(); 51 | ProxyProtocolSpec.initCodeEnum(Command.values(), valuesByCode); 52 | assertEquals(Command.values().length, valuesByCode.size()); 53 | } 54 | 55 | @Test 56 | public void testInitCodeEnum_duplicatedCode() { 57 | thrown.expect(InvalidHeaderException.class); 58 | thrown.expectMessage("0x" + toHexString(TestCode.DUP_1.getCode())); 59 | thrown.expectMessage(TestCode.DUP_1.name()); 60 | thrown.expectMessage(TestCode.DUP_2.name()); 61 | ProxyProtocolSpec.initCodeEnum(TestCode.values(), new HashMap<>()); 62 | } 63 | 64 | @Test 65 | public void testToString() { 66 | assertEquals("PROXY(1)", Command.PROXY.toString()); 67 | } 68 | 69 | private enum TestCode implements Code { 70 | CODE0(0x0), CODE1(0x1), DUP_1(22), DUP_2(22); 71 | 72 | private final int code; 73 | 74 | private TestCode(int code) { 75 | this.code = code; 76 | } 77 | 78 | @Override 79 | public int getCode() { 80 | return code; 81 | } 82 | } 83 | } 84 | 85 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/TlvRawAdapterTest.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file 4 | except in compliance with the License. A copy of the License is located at 5 | 6 | http://aws.amazon.com/apache2.0/ 7 | 8 | or in the "license" file accompanying this file. This file is distributed on an "AS IS" 9 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10 | License for the specific language governing permissions and limitations under the License. 11 | */ 12 | package com.amazonaws.proprot; 13 | 14 | import static org.junit.Assert.assertArrayEquals; 15 | 16 | import java.io.ByteArrayInputStream; 17 | import java.io.ByteArrayOutputStream; 18 | import java.io.DataInputStream; 19 | import java.io.DataOutputStream; 20 | import java.io.IOException; 21 | 22 | import org.junit.Test; 23 | 24 | public class TlvRawAdapterTest { 25 | final TlvRawAdapter adapter = new TlvRawAdapter(8); 26 | 27 | @Test 28 | public void testRead() throws IOException { 29 | DataInputStream in = new DataInputStream(new ByteArrayInputStream( 30 | new byte[] {1, 2, 3, 4})); 31 | TlvRaw tlv = adapter.read(new InputAssist(in, false), 3); 32 | assertArrayEquals(new byte[] {1, 2, 3}, tlv.getValue()); 33 | } 34 | 35 | @Test 36 | public void testWriteValue() throws IOException { 37 | TlvRaw tlv = new TlvRaw(); 38 | byte[] value = new byte[] {1, 2, 3, 4}; 39 | tlv.setValue(value); 40 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 41 | DataOutputStream out = new DataOutputStream(buf); 42 | adapter.writeValue(tlv, out); 43 | assertArrayEquals(value, buf.toByteArray()); 44 | } 45 | @Test 46 | public void testReadEmptyArray() throws IOException { 47 | byte[] expected = new byte[]{}; 48 | DataInputStream in = new DataInputStream(new ByteArrayInputStream(expected)); 49 | TlvRaw tlv = adapter.read(new InputAssist(in, false), 0); 50 | assertArrayEquals(new byte[] {}, tlv.getValue()); 51 | } 52 | 53 | @Test 54 | public void testWriteWithNoValue() throws IOException { 55 | TlvRaw tlv = new TlvRaw(); 56 | tlv.setType(1); 57 | tlv.setValue(new byte[]{}); 58 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 59 | DataOutputStream out = new DataOutputStream(buf); 60 | adapter.writeValue(tlv, out); 61 | assertArrayEquals(new byte[]{}, buf.toByteArray()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /proprot/tst/com/amazonaws/proprot/TlvSubTypeRawAdapterTest.java: -------------------------------------------------------------------------------- 1 | package com.amazonaws.proprot; 2 | 3 | import org.junit.Rule; 4 | import org.junit.Test; 5 | import org.junit.rules.ExpectedException; 6 | 7 | import java.io.ByteArrayInputStream; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.DataInputStream; 10 | import java.io.DataOutputStream; 11 | import java.io.IOException; 12 | 13 | import static org.junit.Assert.assertArrayEquals; 14 | import static org.junit.Assert.assertNull; 15 | 16 | public class TlvSubTypeRawAdapterTest { 17 | final TlvSubTypeRawAdapter subTypeAdapter = new TlvSubTypeRawAdapter(8); 18 | 19 | @Rule 20 | public ExpectedException thrown = ExpectedException.none(); 21 | 22 | @Test 23 | public void testReadSubType() throws IOException { 24 | DataInputStream in = new DataInputStream(new ByteArrayInputStream( 25 | new byte[] { -128, 1, 2, 3, 4})); 26 | TlvSubTypeRaw subTypeTlv = subTypeAdapter.read(new InputAssist(in, false), 4); 27 | assertArrayEquals(new byte[] {1, 2, 3}, subTypeTlv.getValue()); 28 | } 29 | @Test 30 | public void testReadSubTypeWithNoValue() throws IOException { 31 | DataInputStream in = new DataInputStream(new ByteArrayInputStream(new byte[]{-128})); 32 | TlvSubTypeRaw subTypeTlv = subTypeAdapter.read(new InputAssist(in, false), 1); 33 | assertArrayEquals(new byte[] {}, subTypeTlv.getValue()); 34 | } 35 | 36 | @Test 37 | public void testWriteSubTypeWithNoValue() throws IOException { 38 | TlvSubTypeRaw subTypeTlv = new TlvSubTypeRaw(); 39 | subTypeTlv.setType(1); 40 | subTypeTlv.setSubType(128); 41 | subTypeTlv.setValue(new byte[]{}); 42 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 43 | DataOutputStream out = new DataOutputStream(buf); 44 | subTypeAdapter.writeValue(subTypeTlv, out); 45 | assertArrayEquals(new byte[]{-128}, buf.toByteArray()); 46 | } 47 | 48 | @Test 49 | public void testReadSubTypeWithEmptyArray() throws IOException { 50 | thrown.expect(InvalidHeaderException.class); 51 | DataInputStream in = new DataInputStream(new ByteArrayInputStream( 52 | new byte[0])); 53 | TlvSubTypeRaw subTypeTlv = subTypeAdapter.read(new InputAssist(in, false), 0); 54 | assertArrayEquals(new byte[] {}, subTypeTlv.getValue()); 55 | } 56 | 57 | @Test 58 | public void testWriteValueForTlvSubType() throws IOException { 59 | TlvSubTypeRaw tlv = new TlvSubTypeRaw(); 60 | int subType = 128; 61 | byte[] value = new byte[] {1, 2, 3, 4}; 62 | byte[] expectedValue = new byte[] {(byte) subType, 1, 2, 3, 4}; 63 | tlv.setValue(value); 64 | tlv.setSubType(subType); 65 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); 66 | DataOutputStream out = new DataOutputStream(buf); 67 | subTypeAdapter.writeValue(tlv, out); 68 | assertArrayEquals(expectedValue, buf.toByteArray()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /scheduler-lcu-reservation/README.md: -------------------------------------------------------------------------------- 1 | # Scheduler for Load balancer Capacity Unit Reservation 2 | 3 | ## Overview 4 | CloudFormation template for scheduling capacity reservation using the Load balancer Capacity Unit Reservation feature for [Application Load Balancers(ALB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/capacity-unit-reservation.html) and [Network Load Balancers(NLB)](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/capacity-unit-reservation.html) 5 | 6 | 7 | ## Architecture 8 | 9 | ![](capacity-scheduler.drawio.png) 10 | 11 | ## Deployment 12 | 13 | 14 | 1. In the AWS Management Console, go to "CloudFormation" and click "Create stack" 15 | 16 | 1. Select "Upload a template file", choose capacity-reservation-scheduler.yml and click Next 17 | 18 | 1. Fill up the parameters: 19 | 20 | - LoadBalancerArn - The ARN of the ALB or NLB to reserve capacity 21 | - ProvisionedCapacityScheduleStart - Schedule to provision the capacity in [Cron format](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-scheduled-rule-pattern.html) Example: "0 13 * * ? *" for every day at 13:00. 22 | - ProvisionedCapacityScheduleStop - Schedule to reduce or reset the capacity in [Cron format](https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-scheduled-rule-pattern.html) Example: "0 14 * * ? *" for every day at 14:00. 23 | - CapacityReservation - The minimum load balancer capacity to be reserved. 24 | - CapacityReset - The minimum load balancer capacity to return to. Set 0 to reset. 25 | - TimeZone - [OPTIONAL] Timezone for the schedule. Use [IANA convention](https://www.iana.org/time-zones). Example: Australia/Sydney or default to UTC. 26 | - ScheduleGroup - [OPTIONAL] If you have a Schedule Group, add in this field, otherwise leave it blank to create a new one. 27 | - NotificationEmail - [OPTIONAL] E-mail address to receive notification via SNS. 28 | - Tag - [OPTIONAL] Tag to associate with resources. Thee ELB name will be used if left blank. 29 | - StartDate - [OPTIONAL] The date, in UTC (yyyy-MM-ddTHH:mm:ss.SSSZ), before which the schedule will start (immediate if blank). Example: 2024-12-03T01:00:00.000Z 30 | - EndDate - [OPTIONAL] The date, in UTC (yyyy-MM-ddTHH:mm:ss.SSSZ), before which the schedule will end (ignored if blank) 2024-12-04T23:00:00.000Z 31 | 32 | ps: StartDate and EndDate define the time boundary for the whole schedule, whereas ProvisionedCapacityScheduleStart and ProvisionedCapacityScheduleStop define the schedule itself. For example, if StartDate is 2024-12-03T01:00:00.000Z and EndDate is 2024-12-10T01:00:00.000Z, and ProvisionedCapacityScheduleStart is "0 13 * * ? *", it means that starting on 2024-12-03 at 01, there will be a schedule that runs every day at 13:00 until 2024-12-10 at 01. 33 | 34 | 1. Click Next and Next again for the stack creation. 35 | 36 | ## Usage 37 | 38 | Once the schedule stack is deployed, you can check the [ReservedLCUs](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-cloudwatch-metrics.html) metric to see the capacity is reserved according to the schedule. If you input your e-mail, you should also receive notifications (you have to confirm subscription to the SNS topic). 39 | 40 | ## Troubleshooting 41 | 42 | For troubleshooting, use [Lambda Logs](https://docs.aws.amazon.com/lambda/latest/dg/monitoring-cloudwatchlogs-view.html). 43 | 44 | ## License 45 | The Scheduler for Load balancer Capacity Unit Reservation is licensed under the Apache 2.0 License: https://www.apache.org/licenses/LICENSE-2.0 46 | 47 | ## Contributions 48 | 49 | Contributions are welcome. Please check the guidelines on CONTRIBUTING.md -------------------------------------------------------------------------------- /scheduler-lcu-reservation/capacity-scheduler.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /scheduler-lcu-reservation/capacity-scheduler.drawio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/scheduler-lcu-reservation/capacity-scheduler.drawio.png -------------------------------------------------------------------------------- /sharding/README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | CloudFormation template that creates two Route 53 records using weighted routing to split the load accross two load balancers. 4 | 5 | * This template does not create the load balancers, only the Route 53 records 6 | 7 | ## Architecture 8 | 9 | 10 | ![Architecture](images/sharding-diagram.jpg) 11 | 12 | ## Deployment 13 | 14 | 1. In the AWS Management Console, go to "CloudFormation" and click "Create stack" 15 | 16 | 1. Select "Upload a template file", choose elb_ip_monitoring.yml and click Next 17 | 18 | 1. Fill up the parameters: 19 | - **Stack Name** - Any name to identify the stack 20 | - **ELB1DNSName** - DNS Name of the first ELB (Application or Classic) 21 | - **ELB1Weight** - Weight to be used in the DNS record for the first ELB ([Read more](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-weighted.html)) 22 | - **ELB1Type** - The type of the first ELB: Application, Classic or Network 23 | 24 | - **ELB2DNSName** - DNS Name of the second ELB (Application or Classic) 25 | - **ELB2Weight** - Weight to be used in the DNS record for the second ELB ([Read more](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy-weighted.html)) 26 | - **ELB2Type** - The type of the second ELB: Application, Classic or Network 27 | - **HostedZoneId** - The ID of a Route53 hosted zone in the account where the stack will be deployed. This is the hosted zone where a new DNS record will be created pointing to the both load balancers. (e.g. Z1R8UBAEXAMPLE) 28 | - **DNSRecordName** The name (including domain) of the DNS record that will be created and will point to the both load balancers. The domain in this record has to be the same domain in the hosted zone provided in the previous parameter. (e.g. my-shard.example.com) 29 | 30 | 1. Click Next and Next again for the stack creation. 31 | 32 | ![Stack Parameters](images/stack-parameters.png) 33 | 34 | ## Usage 35 | 36 | Once the stack is created, you can navigate to Route 53 console, open the Hosted Zone and you will see the new records created using Weighted routing policy. 37 | 38 | ![Records in the Hosted zone](images/sharding-route53.png) 39 | 40 | # Testing 41 | 42 | ``` 43 | $ dig my-shard.example.com +short 44 | 198.51.100.13 # Example IP of ELB 1 45 | 198.51.100.27 # Example IP of ELB 1 46 | 47 | run again: 48 | 49 | $ dig my-shard.example.com +short 50 | 203.0.113.71 # Example IP of ELB 2 51 | 203.0.113.28 # Example IP of ELB 2 52 | ``` 53 | 54 | With an equal weight in both records, each time you perform a DNS resolution there will be a 50% chance of returning the IPs of ELB 1 and 50% chance of returning the Ips of ELB 2. 55 | -------------------------------------------------------------------------------- /sharding/elb_sharding.yml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: CloudFormation template to create a DNS record with a weighted policy pointing to two ELBs. 3 | 4 | Metadata: 5 | AWS::CloudFormation::Interface: 6 | ParameterGroups: 7 | - 8 | Label: 9 | default: "First ELB" 10 | Parameters: 11 | - ELB1DNSName 12 | - ELB1Type 13 | - ELB1Weight 14 | - 15 | Label: 16 | default: "Second ELB" 17 | Parameters: 18 | - ELB2DNSName 19 | - ELB2Type 20 | - ELB2Weight 21 | - 22 | Label: 23 | default: "Route 53 Hosted Zone details" 24 | Parameters: 25 | - DNSHostedZoneId 26 | - DNSRecordName 27 | 28 | 29 | Parameters: 30 | ELB1DNSName: 31 | Description: DNS Name of Elastic Load Balancer 1 (e.g. my-load-balancer1-1234567890.us-west-2.elb.amazonaws.com) 32 | Type: String 33 | MinLength: '1' 34 | ELB1Type: 35 | Description: Type of Elastic Load Balancer 1 36 | Type: String 37 | Default: "Application/Classic" 38 | AllowedValues: 39 | - "Application/Classic" 40 | - "Network" 41 | ELB1Weight: 42 | Description: Weight for Elastic Load Balancer 1 43 | Type: Number 44 | MinValue: 0 45 | MaxValue: 255 46 | Default: 50 47 | ELB2DNSName: 48 | Description: DNS Name of Elastic Load Balancer 2 (e.g. my-load-balancer2-0987654321.us-west-2.elb.amazonaws.com) 49 | Type: String 50 | MinLength: '1' 51 | ELB2Type: 52 | Description: Type of Elastic Load Balancer 2 53 | Type: String 54 | Default: "Application/Classic" 55 | AllowedValues: 56 | - "Application/Classic" 57 | - "Network" 58 | ELB2Weight: 59 | Description: Weight for Elastic Load Balancer 2 60 | Type: Number 61 | MinValue: 0 62 | MaxValue: 255 63 | Default: 50 64 | DNSHostedZoneId: 65 | Description: The ID of the Route 53 hosted zone (e.g. Z1R8UBAEXAMPLE) 66 | Type: String 67 | DNSRecordName: 68 | Description: The DNS record name to be used. It has to be a new record and the domain name has belong to the hosted zone provided in the previous parameter (e.g. my-shard.example.com) 69 | Type: String 70 | 71 | Mappings: 72 | ELBHostedZoneMapping: 73 | us-east-2: 74 | "ALBHostedZoneID": "Z3AADJGX6KTTL2" 75 | "NLBHostedZoneID": "ZLMOA37VPKANP" 76 | us-east-1: 77 | "ALBHostedZoneID": "Z35SXDOTRQ7X7K" 78 | "NLBHostedZoneID": "Z26RNL4JYFTOTI" 79 | us-west-1: 80 | "ALBHostedZoneID": "Z368ELLRRE2KJ0" 81 | "NLBHostedZoneID": "Z24FKFUX50B4VW" 82 | us-west-2: 83 | "ALBHostedZoneID": "Z1H1FL5HABSF5" 84 | "NLBHostedZoneID": "Z18D5FSROUN65G" 85 | af-south-1: 86 | "ALBHostedZoneID": "Z268VQBMOI5EKX" 87 | "NLBHostedZoneID": "Z203XCE67M25HM" 88 | ap-east-1: 89 | "ALBHostedZoneID": "Z3DQVH9N71FHZ0" 90 | "NLBHostedZoneID": "Z12Y7K3UBGUAD1" 91 | ap-south-2: 92 | "ALBHostedZoneID": "Z0173938T07WNTVAEPZN" 93 | "NLBHostedZoneID": "Z0711778386UTO08407HT" 94 | ap-southeast-3: 95 | "ALBHostedZoneID": "Z08888821HLRG5A9ZRTER" 96 | "NLBHostedZoneID": "Z01971771FYVNCOVWJU1G" 97 | ap-southeast-4: 98 | "ALBHostedZoneID": "Z09517862IB2WZLPXG76F" 99 | "NLBHostedZoneID": "Z01156963G8MIIL7X90IV" 100 | ap-south-1: 101 | "ALBHostedZoneID": "ZP97RAFLXTNZK" 102 | "NLBHostedZoneID": "ZVDDRBQ08TROA" 103 | ap-northeast-3: 104 | "ALBHostedZoneID": "Z5LXEXXYW11ES" 105 | "NLBHostedZoneID": "Z1GWIQ4HH19I5X" 106 | ap-northeast-2: 107 | "ALBHostedZoneID": "ZWKZPGTI48KDX" 108 | "NLBHostedZoneID": "ZIBE1TIR4HY56" 109 | ap-southeast-1: 110 | "ALBHostedZoneID": "Z1LMS91P8CMLE" 111 | "NLBHostedZoneID": "ZKVM4W9LS7TM" 112 | ap-southeast-2: 113 | "ALBHostedZoneID": "Z1GM3OXH4ZPM65" 114 | "NLBHostedZoneID": "ZCT6FZBF4DROD" 115 | ap-northeast-1: 116 | "ALBHostedZoneID": "Z14GRHDCWA56QT" 117 | "NLBHostedZoneID": "Z31USIVHYNEOWT" 118 | ca-central-1: 119 | "ALBHostedZoneID": "ZQSVJUPU6J1EY" 120 | "NLBHostedZoneID": "Z2EPGBW3API2WT" 121 | cn-north-1: 122 | "ALBHostedZoneID": "Z1GDH35T77C1KE" 123 | "NLBHostedZoneID": "Z3QFB96KMJ7ED6" 124 | cn-northwest-1: 125 | "ALBHostedZoneID": "ZM7IZAIOVVDZF" 126 | "NLBHostedZoneID": "ZQEIKTCZ8352D" 127 | eu-central-1: 128 | "ALBHostedZoneID": "Z215JYRZR1TBD5" 129 | "NLBHostedZoneID": "Z3F0SRJ5LGBH90" 130 | eu-west-1: 131 | "ALBHostedZoneID": "Z32O12XQLNTSW2" 132 | "NLBHostedZoneID": "Z2IFOLAFXWLO4F" 133 | eu-west-2: 134 | "ALBHostedZoneID": "ZHURV8PSTC4K8" 135 | "NLBHostedZoneID": "ZD4D7Y8KGAS4G" 136 | eu-south-1: 137 | "ALBHostedZoneID": "Z3ULH7SSC9OV64" 138 | "NLBHostedZoneID": "Z23146JA1KNAFP" 139 | eu-west-3: 140 | "ALBHostedZoneID": "Z3Q77PNBQS71R4" 141 | "NLBHostedZoneID": "Z1CMS0P5QUZ6D5" 142 | eu-south-2: 143 | "ALBHostedZoneID": "Z0956581394HF5D5LXGAP" 144 | "NLBHostedZoneID": "Z1011216NVTVYADP1SSV" 145 | eu-north-1: 146 | "ALBHostedZoneID": "Z23TAZ6LKFMNIO" 147 | "NLBHostedZoneID": "Z1UDT6IFJ4EJM" 148 | eu-central-2: 149 | "ALBHostedZoneID": "Z06391101F2ZOEP8P5EB3" 150 | "NLBHostedZoneID": "Z02239872DOALSIDCX66S" 151 | il-central-1: 152 | "ALBHostedZoneID": "Z09170902867EHPV2DABU" 153 | "NLBHostedZoneID": "Z0313266YDI6ZRHTGQY4" 154 | me-south-1: 155 | "ALBHostedZoneID": "ZS929ML54UICD" 156 | "NLBHostedZoneID": "Z3QSRYVP46NYYV" 157 | me-central-1: 158 | "ALBHostedZoneID": "Z08230872XQRWHG2XF6I" 159 | "NLBHostedZoneID": "Z00282643NTTLPANJJG2P" 160 | sa-east-1: 161 | "ALBHostedZoneID": "Z2P70J7HTTTPLU" 162 | "NLBHostedZoneID": "ZTK26PT1VY4CU" 163 | us-gov-east-1: 164 | "ALBHostedZoneID": "Z166TLBEWOO7G0" 165 | "NLBHostedZoneID": "Z1ZSMQQ6Q24QQ8" 166 | us-gov-west-1: 167 | "ALBHostedZoneID": "Z33AYJ8TM3BH4J" 168 | "NLBHostedZoneID": "ZMG1MZ2THAWF1" 169 | 170 | Conditions: 171 | IsNLB1: !Equals [!Ref ELB1Type, "Network"] 172 | IsNLB2: !Equals [!Ref ELB2Type, "Network"] 173 | 174 | Resources: 175 | ELB1DNSRecord: 176 | Type: 'AWS::Route53::RecordSet' 177 | Properties: 178 | HostedZoneId: !Ref DNSHostedZoneId 179 | Name: !Ref DNSRecordName 180 | Type: A 181 | AliasTarget: 182 | DNSName: !Ref ELB1DNSName 183 | EvaluateTargetHealth: true 184 | HostedZoneId: 185 | !If 186 | - IsNLB1 187 | - !FindInMap [ELBHostedZoneMapping, !Ref "AWS::Region", "NLBHostedZoneID"] # https://docs.aws.amazon.com/general/latest/gr/elb.html 188 | - !FindInMap [ELBHostedZoneMapping, !Ref "AWS::Region", "ALBHostedZoneID"] # https://docs.aws.amazon.com/general/latest/gr/elb.html 189 | SetIdentifier: ELB1 190 | Weight: !Ref ELB1Weight 191 | 192 | ELB2DNSRecord: 193 | Type: 'AWS::Route53::RecordSet' 194 | Properties: 195 | HostedZoneId: !Ref DNSHostedZoneId 196 | Name: !Ref DNSRecordName 197 | Type: A 198 | AliasTarget: 199 | DNSName: !Ref ELB2DNSName 200 | EvaluateTargetHealth: true 201 | HostedZoneId: 202 | !If 203 | - IsNLB2 204 | - !FindInMap [ELBHostedZoneMapping, !Ref "AWS::Region", "NLBHostedZoneID"] # https://docs.aws.amazon.com/general/latest/gr/elb.html 205 | - !FindInMap [ELBHostedZoneMapping, !Ref "AWS::Region", "ALBHostedZoneID"] # https://docs.aws.amazon.com/general/latest/gr/elb.html 206 | 207 | SetIdentifier: ELB2 208 | Weight: !Ref ELB2Weight 209 | -------------------------------------------------------------------------------- /sharding/images/sharding-diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/sharding/images/sharding-diagram.jpg -------------------------------------------------------------------------------- /sharding/images/sharding-route53.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/sharding/images/sharding-route53.png -------------------------------------------------------------------------------- /sharding/images/stack-parameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws/elastic-load-balancing-tools/7cc55a948ec085ce8c4e2dde60a12eb9c0f55262/sharding/images/stack-parameters.png --------------------------------------------------------------------------------