spring-vault.md 102.8 KB
Newer Older
dallascao's avatar
dallascao 已提交
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089
# Spring 保险库-参考文献

# [](#preface)序言

Spring Vault 项目将核心 Spring 概念应用于使用 HashiCorpVault 的解决方案的开发。我们提供了一个“模板”作为存储和查询文档的高级抽象。你将注意到与 Spring 框架中的 REST 支持的相似之处。

这份文件是 Spring Vault 的参考指南。它解释了 Vault 的概念、语义和语法。

参考文档的这一部分解释了 Spring Vault 提供的核心功能。

[保险库支持](#vault.core)介绍了 Vault 模块功能集。

## [](#preface.document-structure)1。文件结构

这一部分提供了 Spring 和 Vault 的基本介绍。它包含有关后续开发和如何获得支持的详细信息。

文档的其余部分引用了 Spring Vault 特性,并假定用户熟悉[HashiCorp 保险库](https://www.vaultproject.io)以及 Spring 概念。

## [](#get-started:first-steps:spring)2。知道 Spring

Spring Vault 使用 Spring Framework 的[core](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference/core.html)功能,例如[IoC](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference//core.html)容器。虽然了解 Spring API 并不重要,但了解它们背后的概念是重要的。至少,对于你选择使用的任何 IOC 容器,IOC 背后的思想应该是熟悉的。

Vault 支持的核心功能可以直接使用,而不需要调用 Spring 容器的 IoC 服务。这很像`RestTemplate`,它可以在没有 Spring 容器的任何其他服务的情况下“独立”使用。为了利用 Spring Vault 文档的所有特性,例如会话支持,你将需要使用 Spring 配置库的某些部分。

要了解有关 Spring 的更多信息,你可以参考详细解释 Spring 框架的全面(有时是解除武装)文档。有很多关于这个问题的文章、博客条目和书籍--看看 Spring 框架[home page ](https://spring.io/docs),了解更多信息。

## [](#get-started:first-steps:vault)3。知道保险库

安全性和处理秘密是每个处理数据库、用户凭据或 API 密钥的开发人员关心的问题。Vault 通过提供与访问控制、撤销、密钥滚动和审计相结合的安全存储来介入。简而言之:Vault 是一种安全访问和存储秘密的服务。秘密是你想要严格控制访问权限的任何东西,例如 API 密钥、密码、证书等等。

学习跳马的起点是[WWW,VaultProject.io。](https://www.vaultproject.io)。以下是一些有用的资源:

* 该手册介绍了 Vault,并包含入门指南、参考文档和教程的链接。

* Online Shell 结合在线教程提供了一种方便的方式来与 Vault 实例交互。

* [HashiCorp 保险库介绍](https://www.vaultproject.io/intro/index.html)

* [HashiCorp 保险库文档](https://www.vaultproject.io/docs/index.html)

Spring Vault 提供了用于访问、存储和撤销秘密的客户端支持。有了[HashiCorp 的保险库](https://www.vaultproject.io),你就有了一个中心位置来管理跨所有环境的应用程序的外部秘密数据。Vault 可以管理静态和动态秘密,例如应用程序数据、远程应用程序/资源的用户名/密码,并为外部服务(例如 MySQL、PostgreSQL、 Apache Cassandra、Consul、AWS 等)提供凭据。

## [](#requirements)4。所需经费

Spring Vault2.x 二进制文件要求 JDK 级别为 8.0 及以上,并且[Spring Framework](https://spring.io/docs)5.3.4 及以上。

就保险库而言,[Vault](https://www.vaultproject.io/)至少为 0.6。

## [](#get-started:additional-help)5。额外的帮助资源

学习一个新的框架并不总是直截了当的。在这一部分中,我们试图提供一种我们认为易于遵循的指南,用于从 Spring Vault 模块开始。然而,如果你遇到问题或你只是在寻求建议,请使用以下链接之一:

### [](#get-started:help)5.1。支持

有几个可用的支持选项:

#### [](#get-started:help:community)5.1.1。社区论坛

[StackOverflow](https://stackoverflow.com/questions/tagged/spring-vault)上发布有关 Spring Vault 的问题,以共享信息并相互帮助。请注意,需要注册**只有**才能发布。

#### [](#get-started:help:professional)5.1.2。专业支持

Spring Vault 和 Spring 背后的公司[Pivotal Software,Inc.](https://pivotal.io/)提供专业的、源代码支持,并保证响应时间。

### [](#get-started:up-to-date)5.2。后续发展

有关 Spring Vault 源代码库、夜间构建和快照工件的信息,请参见[Spring Vault homepage](https://projects.spring.io/spring-vault/)。通过在[StackOverflow](https://stackoverflow.com/questions/tagged/spring-vault)上通过社区与开发人员进行交互,你可以帮助使 Spring Vault 最好地满足 Spring 社区的需求。如果你遇到错误或希望提出改进建议,请在 Spring vault 问题[tracker](https://github.com/spring-projects/spring-vault/issues)上创建一个票证。要了解 Spring 生态系统中的最新消息和公告,请订阅 Spring 社区[Portal](https://spring.io)。最后,你可以关注 Spring [blog ](https://spring.io/blog)或 Twitter 上的项目团队([SpringCentral](https://twitter.com/springcentral))。

## [](#new-features)6。新的和值得注意的

### [](#new-features.2-3-0)6.1。最新更新在 Spring Vault2.3 中

* 支持用于密钥库和信任库使用的 PEM 编码证书。

* `ReactiveVaultEndpointProvider`用于`VaultEndpoint`的非阻塞查找。

* `VaultKeyValueMetadataOperations`用于键值元数据交互。

* 支持`transform`后端(Enterprise 功能)。

* [如何使用保险库秘密后端](#vault.core.secret-engines)的文档。

* 每次登录尝试都会重新加载 Kubernetes 和 PCF 身份验证的登录凭据。

* `SecretLeaseContainer`在成功的秘密旋转时发布`SecretLeaseRotatedEvent`而不是`SecretLeaseExpiredEvent``SecretLeaseCreatedEvent`

* `AbstractVaultConfiguration.threadPoolTaskScheduler()` Bean 类型更改为`TaskSchedulerWrapper`而不是`ThreadPoolTaskScheduler`

### [](#new-features.2-2-0)6.2。最新更新在 Spring Vault2.2 中

* 通过`@VaultPropertySource`支持键值 v2(版本控制的后端)秘密。

* spel 支持`@Secret`

* 添加对 Jetty 的支持作为反应性 HttpClient。

* `LifecycleAwareSessionManager``ReactiveLifecycleAwareSessionManager`现在发射`AuthenticationEvent`s。

* [PCF 认证](#vault.authentication.pcf).

* 反对`AppIdAuthentication`。使用`AppRoleAuthentication`,而不是按照 HashiCorp 保险库的建议。

* `CubbyholeAuthentication`和 wrapped`AppRoleAuthentication`现在默认使用`sys/wrapping/unwrap`端点。

* Kotlin 协程支持`ReactiveVaultOperations`

### [](#new-features.2-1-0)6.3。最新更新在 Spring Vault2.1 中

* [GCP 计算](#vault.authentication.gcpgce)[GCP IAM](#vault.authentication.gcpiam),以及[Azure](#vault.authentication.azuremsi)身份验证。

* 模板 API 支持版本控制和非版本控制的键/值后端和 Vault 包装操作。

* 在反应式认证中支持完全拉动模式.

* 改进了保险库登录失败的异常层次结构。

### [](#new-features.2-0-0)6.4。最新更新在 Spring Vault2.0 中

* 身份验证步骤 dsl 到[组合认证流](#vault.authentication.steps)

* [反应式保险库客户端](#vault.core.reactive.template)via`ReactiveVaultOperations`

* 基于 Spring 数据键值的[保险库存储库支持](#vault.repositories)

* 支持传输批加密和解密.

* 存储为 JSON 的策略的策略管理。

* 支持 CSR 签名、证书撤销和 CRL 检索。

* [Kubernetes 认证](#vault.authentication.kubernetes).

* roleid/secretid 展开[Approle 身份验证](#vault.authentication.approle)

* [Spring Security integration](#vault.misc.spring-security)基于传输后端的`BytesKeyGenerator``BytesEncryptor`

### [](#new-features.1-1-0)6.5。最新更新在 Spring Vault1.1.0 中

* [AWS IAM 身份验证](#vault.authentication.awsiam).

* 为传输密钥配置加密/解密版本。

* [Approle 身份验证](#vault.authentication.approle)的拉动模式。

* 支持传输批加密和解密.

* 基于 TTL 的通用秘密旋转。

### [](#new-features.1-0-0)6.6。最新更新在 Spring Vault1.0 中

* 最初的保险库支持。

# [](#reference-documentation)参考文献

## [](#vault.core)7。保险库支持

Vault 支持包含一系列广泛的功能,这些功能概述如下。

* Spring 使用基于 Java 的配置支持 @Configuration Classes

* `VaultTemplate`帮助类,用于提高执行公共保险库操作的生产率。包括保险库响应和 POJO 之间的集成对象映射。

对于大多数任务,你会发现自己正在使用`VaultTemplate`,它利用了丰富的通信功能。`VaultTemplate`是查找访问功能(例如从 Vault 读取数据或发出管理命令)的位置。`VaultTemplate`还提供了回调方法,这样你就可以轻松地获得低级 API 工件,例如`RestTemplate`,从而直接与 Vault 通信。

### [](#dependencies)7.1。依赖关系

查找 Spring Vault 依赖关系的兼容版本的最简单的方法是依赖于我们提供的 Spring Vault BOM 以及定义的兼容版本。在 Maven 项目中,你将在你的`pom.xml``<dependencyManagement />`部分中声明此依赖项:

例 1。使用 Spring 保险库 BOM

```
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.vault</groupId>
      <artifactId>spring-vault-dependencies</artifactId>
      <version>2.3.1</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>
```

目前的版本是`2.3.1`。版本名遵循以下模式:`${version}`用于 GA 和服务版本,`${version}-${release}`用于快照和里程碑。`release`可以是下列情况之一:

* `SNAPSHOT`-当前快照

* `M1``M2`等-里程碑

* `RC1``RC2`等-释放候选项

例 2。声明对 Spring Vault 的依赖关系

```
<dependencies>
    <dependency>
        <groupId>org.springframework.vault</groupId>
        <artifactId>spring-vault-core</artifactId>
    </dependency>
</dependencies>
```

### [](#dependencies.spring-framework)7.2。 Spring 框架

Spring Vault 的当前版本需要版本 5.3.4 或更好的 Spring 框架。这些模块还可以与该小版本的旧 Bugfix 版本一起工作。但是,强烈建议你在这一代中使用最新的版本。

## [](#vault.core.getting-started)8。开始

Spring Vault 支持需要 Vault0.6 或更高版本和 Java SE6 或更高版本。引导设置工作环境的一种简单方法是在[STS](https://spring.io/tools/sts)中创建一个基于 Spring 的项目。

首先,你需要设置一个运行的保险库服务器。有关如何启动 Vault 实例的说明,请参阅[Vault](https://www.vaultproject.io/intro/)

要在 STS 中创建 Spring 项目,请转到文件 New Spring Template Project Simple Spring Utility Project,在提示时按 Yes。然后输入一个项目和一个包名,如`org.spring.vault.example`

然后将以下内容添加到`pom.xml`依赖关系部分。

例 3。添加 Spring 保险库依赖项

```
<dependencies>

  <!-- other dependency elements omitted -->

  <dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
    <version>2.3.1</version>
  </dependency>

</dependencies>
```

如果你正在使用一个里程碑或候选版本,那么你还需要将 Spring 里程碑存储库的位置添加到你的 Maven `pom.xml`中,该位置与你的`<dependencies/>`元素处于同一级别。

```
<repositories>
  <repository>
    <id>spring-milestone</id>
    <name>Spring Maven MILESTONE Repository</name>
    <url>https://repo.spring.io/libs-milestone</url>
  </repository>
</repositories>
```

存储库也是[在这里可浏览](https://repo.spring.io/milestone/org/springframework/vault/)

如果正在使用快照,还需要将 Spring 快照库的位置添加到你的 Maven `pom.xml`中,该位置与你的`<dependencies/>`元素处于同一级别。

```
<repositories>
  <repository>
    <id>spring-snapshot</id>
    <name>Spring Maven SNAPSHOT Repository</name>
    <url>https://repo.spring.io/libs-snapshot</url>
  </repository>
</repositories>
```

存储库也是[在这里可浏览](https://repo.spring.io/snapshot/org/springframework/vault/)

创建一个简单的`Secrets`类以持久存在:

例 4。映射数据对象

```
package org.spring.vault.example;

public class Secrets {

    String username;
    String password;

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}
```

以及要运行的主应用程序

例 5。使用 Spring Vault 的示例应用程序

```
package org.springframework.vault.example;

import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.client.VaultEndpoint;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponseSupport;

public class VaultApp {

    public static void main(String[] args) {

        VaultTemplate vaultTemplate = new VaultTemplate(new VaultEndpoint(),
                new TokenAuthentication("00000000-0000-0000-0000-000000000000"));

        Secrets secrets = new Secrets();
        secrets.username = "hello";
        secrets.password = "world";

        vaultTemplate.write("secret/myapp", secrets);

        VaultResponseSupport<Secrets> response = vaultTemplate.read("secret/myapp", Secrets.class);
        System.out.println(response.getData().getUsername());

        vaultTemplate.delete("secret/myapp");
    }
}
```

即使在这个简单的例子中,也没有什么值得注意的地方。

* 可以使用`org.springframework.vault.client.VaultEndpoint`对象和`ClientAuthentication`实例化 Spring Vault 的中心类[`VaultTemplate`](#vault.core.template)。你不需要旋转 Spring 上下文来使用 Spring vault。

* Vault 将被配置为使用`00000000-0000-0000-0000-000000000000`的根令牌来运行此应用程序。

* 该映射器针对标准的 POJO 对象工作,而不需要任何额外的元数据(尽管你可以选择提供该信息)。

* 映射约定可以使用字段访问。注意`Secrets`类只有 getter。

* 如果构造函数参数名称与存储文档的字段名称匹配,则将使用它们实例化对象。

## [](#vault.core.template)9。VaultTemplate 简介

`VaultTemplate`位于包`org.springframework.vault.core`中,是 Spring 的 Vault 支持的中心类,提供了与 Vault 交互的丰富功能集。该模板提供了在 Vault 中读、写和删除数据的方便操作,并提供了域对象和 Vault 数据之间的映射。

|   |一旦配置完成,`VaultTemplate`是线程安全的,并且可以在<br/>多个实例中重用。|
|---|------------------------------------------------------------------------------------------------|

Vault 文档和域类之间的映射是通过委托给`RestTemplate`来完成的。 Spring Web 支持提供了映射基础设施。

`VaultTemplate`类实现了接口`VaultOperations`。在尽可能多的情况下,`VaultOperations`上的方法是以 Vault API 上可用的方法命名的,以使熟悉 API 和 CLI 的现有 Vault 开发人员熟悉该 API。例如,你将找到诸如“write”、“delete”、“read”和“revoke”等方法。设计目标是使 Vault API 的使用和`VaultOperations`之间的转换变得尽可能容易。这两个 API 之间的一个主要区别是,`VaultOperations`可以传递域对象,而不是 JSON 键-值对。

|   |引用`VaultTemplate`实例<br/>上的操作的首选方法是通过其接口`VaultOperations`。|
|---|---------------------------------------------------------------------------------------------------------------------|

虽然在`VaultTemplate`上有许多方便的方法可以帮助你轻松地执行常见任务,如果你需要直接访问 Vault API 以访问`VaultTemplate`未显式暴露的功能,则可以使用几种执行回调方法中的一种来访问底层 API。Execute 回调将为你提供对`RestOperations`对象的引用。有关更多信息,请参见[执行回调](#vault.core.executioncallback)一节。

现在,让我们来看看如何在 Spring 容器的上下文中使用 Vault 的示例。

### [](#vault.core.template.beans)9.1。注册和配置 Spring Vault bean

使用 Spring Vault 不需要 Spring 上下文。但是,在托管上下文中注册的`VaultTemplate``SessionManager`实例将参与由 Spring IOC 容器提供的[生命周期事件](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference/core.html#beans-factory-nature)。这对于在应用程序关闭时处理活动的 Vault 会话非常有用。你还可以在应用程序中重用相同的`VaultTemplate`实例。

Spring Vault 附带了一个支持配置类,该配置类提供了 Bean 用于在 Spring 上下文中使用的定义。应用程序配置类通常从`AbstractVaultConfiguration`扩展,并且需要提供环境特定的附加细节。

`AbstractVaultConfiguration`扩展需要实现` VaultEndpoint vaultEndpoint()``ClientAuthentication clientAuthentication()`方法。

例 6。使用基于 Java 的 Bean 元数据注册 Spring Vault 对象

```
@Configuration
public class AppConfig extends AbstractVaultConfiguration {

    /**
     * Specify an endpoint for connecting to Vault.
     */
    @Override
    public VaultEndpoint vaultEndpoint() {
        return new VaultEndpoint();                            (1)
    }

    /**
     * Configure a client authentication.
     * Please consider a more secure authentication method
     * for production use.
     */
    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("…");                   (2)
    }
}
```

|**1**|创建一个新的`VaultEndpoint`,默认情况下指向`https://localhost:8200`。|
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|此示例使用`TokenAuthentication`快速启动。<br/>有关支持的身份验证方法的详细信息,请参见[认证方法](#vault.core.authentication)。|

例 7。使用注入的财产登记 Spring 保险库

```
@Configuration
public class AppConfig extends AbstractVaultConfiguration {

    @Value("${vault.uri}")
    URI vaultUri;

    /**
     * Specify an endpoint that was injected as URI.
     */
    @Override
    public VaultEndpoint vaultEndpoint() {
        return VaultEndpoint.from(vaultUri);                          (1)
    }

    /**
     * Configure a Client Certificate authentication.
     * {@link RestOperations} can be obtained from {@link #restOperations()}.
     */
    @Override
    public ClientAuthentication clientAuthentication() {
        return new ClientCertificateAuthentication(restOperations()); (2)
    }
}
```

|**1**|`VaultEndpoint`可以使用各种工厂方法构建,例如`from(URI uri)``VaultEndpoint.create(String host, int port)`。|
|-----|------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|`ClientAuthentication`方法的依赖关系可以从`AbstractVaultConfiguration`获得,也可以由配置提供。|

|   |在某些情况下,创建自定义配置类可能很麻烦。<br/>看看`EnvironmentVaultConfiguration`,它允许使用现有属性源的<br/>属性和 Spring 的`Environment`进行配置。在[using`EnvironmentVaultConfiguration`](#vault.core.environment-vault-configuration)中阅读更多<br/>。|
|---|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### [](#vault.core.template.sessionmanagement)9.2。会话管理

Spring Vault 需要`ClientAuthentication`才能登录和访问 Vault。有关身份验证的详细信息,请参见[认证方法](#vault.core.authentication)。Vault 登录不应该发生在每个经过身份验证的 Vault 交互上,而是必须在整个会话中重用。该方面由`SessionManager`实现来处理。a`SessionManager`决定它获得令牌的频率,关于撤销和更新。 Spring Vault 有两种实现方式:

* `SimpleSessionManager`:只需从提供的`ClientAuthentication`获取令牌,而无需刷新和撤销

* `LifecycleAwareSessionManager`:如果令牌是可更新的,则此`SessionManager`调度令牌更新,并在处置时撤销登录令牌。更新计划使用`AsyncTaskExecutor`。如果使用`AbstractVaultConfiguration`,则默认配置`LifecycleAwareSessionManager`

### [](#vault.core.environment-vault-configuration)9.3。使用`EnvironmentVaultConfiguration`

Spring Vault 包括从 Spring 的`Environment`中配置 Vault 客户端的`EnvironmentVaultConfiguration`和一组预定义的属性键。`EnvironmentVaultConfiguration`支持经常应用的配置。从最合适的配置类派生支持其他配置。将`EnvironmentVaultConfiguration``@Import(EnvironmentVaultConfiguration.class)`一起包含到现有的基于 Java 的配置类中,并通过 Spring 的`PropertySource`s 中的任何一个提供配置属性。

例 8。对属性文件使用 EnvironmentVaultConfiguration

基于 Java 的配置类

```
@PropertySource("vault.properties")
@Import(EnvironmentVaultConfiguration.class)
public class MyConfiguration{
}
```

Vault.Properties

```
vault.uri=https://localhost:8200
vault.token=00000000-0000-0000-0000-000000000000
```

**属性键**

* Vault URI:`vault.uri`

* SSL 配置

  * 密钥存储库资源:`vault.ssl.key-store`(可选)

  * 密钥存储库密码:`vault.ssl.key-store-password`(可选)

  * 密钥存储库类型:`vault.ssl.key-store-type`(可选的,通常`jks`,还支持`pem`

  * 信任存储资源:`vault.ssl.trust-store`(可选)

  * 信任存储库密码:`vault.ssl.trust-store-password`(可选)

  * 信任存储类型:`vault.ssl.trust-store-type`(可选的,通常`jks`,也支持`pem`

* 认证方法:`vault.authentication`(默认为`TOKEN`,支持的认证方法有:`TOKEN``APPID``APPROLE``AWS_EC2``AZURE``CUBBYHOLE``KUBERNETES`

**特定于身份验证的属性密钥**

**[令牌认证](#vault.authentication.token)**

* 金库令牌:`vault.token`

**[APPID 身份验证](#vault.authentication.appid)**

* APPID 路径:`vault.app-id.app-id-path`(默认为`app-id`

* appid:`vault.app-id.app-id`

* userid:`vault.app-id.user-id``MAC_ADDRESS``IP_ADDRESS`使用`MacAddressUserId`,相应的`IpAddressUserId`用户 ID 机制。任何其他值都与`StaticUserId`一起使用。

**[Approle 身份验证](#vault.authentication.approle)**

* 路径:`vault.app-role.app-role-path`(默认为`approle`

* ROLEID:`vault.app-role.role-id`

* secretID:`vault.app-role.secret-id`(可选)

**[AWS-EC2 身份验证](#vault.authentication.awsec2)**

* AWS EC2 路径:`vault.aws-ec2.aws-ec2-path`(默认为`aws-ec2`

* 角色:`vault.aws-ec2.role`

* ROLEID:`vault.aws-ec2.role-id`** 不推荐:**`vault.aws-ec2.role`代替)

* 身份证件网址:`vault.aws-ec2.identity-document`(默认为`[http://169.254.169.254/latest/dynamic/instance-identity/pkcs7](http://169.254.169.254/latest/dynamic/instance-identity/pkcs7)`

**[Azure(MSI)认证](#vault.authentication.azuremsi)**

* Azure MSI 路径:`vault.azure-msi.azure-path`(默认为`azure`

* 角色:`vault.azure-msi.role`

* 元数据服务 URL:`vault.azure-msi.metadata-service`(默认为`[http://169.254.169.254/metadata/instance?api-version=2017-08-01](http://169.254.169.254/metadata/instance?api-version=2017-08-01)`

* Identity TokenService URL:`vault.azure-msi.identity-token-service`(默认为`[http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.hashicorp.com&api-version=2018-02-01](http://169.254.169.254/metadata/identity/oauth2/token?resource=https://vault.hashicorp.com&api-version=2018-02-01)`

**[TLS 证书认证](#vault.authentication.clientcert)**

没有配置选项。

**[空穴身份验证](#vault.authentication.cubbyhole)**

* 初始保险库令牌:`vault.token`

**[Kubernetes 认证](#vault.authentication.kubernetes)**

* Kubernetes 路径:`vault.kubernetes.kubernetes-path`(默认为`kubernetes`

* 角色:`vault.kubernetes.role`

* 服务帐户令牌文件的路径:`vault.kubernetes.service-account-token-file`(默认为`/var/run/secrets/kubernetes.io/serviceaccount/token`

### [](#vault.core.executioncallback)9.4。执行回调

所有 Spring 模板类的一个常见设计特征是,所有功能都被路由到一个模板执行回调方法。这有助于确保执行异常和可能需要的任何资源管理的一致性。虽然在 JDBC 和 JMS 的情况下,这比 Vault 的需要大得多,但它仍然为访问和日志记录的发生提供了一个单一的位置。因此,使用 Execute Callback 是访问 Vault API 的首选方式,以执行我们尚未作为`VaultTemplate`上的方法公开的不常见操作。

下面是执行回调方法的列表。

* `<T> T`**DowithVault**`(RestOperationsCallback<T> callback)`执行给定的`RestOperationsCallback`,允许使用`RestOperations`与 Vault 进行交互,而不需要会话。

* `<T> T`**首次会议**`(RestOperationsCallback<T> callback)`执行给定的`RestOperationsCallback`,允许在经过身份验证的保险库中进行交互会话。

下面是一个使用`ClientCallback`初始化 Vault 的示例:

```
vaultOperations.doWithVault(new RestOperationsCallback<VaultInitializationResponse>() {

  @Override
  public VaultInitializationResponse doWithRestOperations(RestOperations restOperations) {

    ResponseEntity<VaultInitializationResponse> exchange = restOperations
                       .exchange("/sys/init", HttpMethod.PUT,
                                 new HttpEntity<Object>(request),
                                 VaultInitializationResponse.class);

    return exchange.getBody();
    }
});
```

## [](#vault.core.secret-engines)10。支持 Vault 的秘密引擎

Spring Vault 船有几个扩展,以支持 Vault 的各种秘密引擎。

具体地说, Spring 带有扩展的保险库船舶用于:

* [键值版本 1(“无版本的秘密”)](#vault.core.backends.kv1)

* [键值版本 2(“版本管理的秘密”)](#vault.core.backends.kv2)

* [PKI(公开密钥基础设施)](#vault.core.backends.pki)

* [令牌认证后端](#vault.core.backends.token)

* 转换(Enterprise 特性)

* [传输后端](#vault.core.backends.transit)

* 系统后端

你可以通过`VaultTemplate`上的方法直接使用所有其他后端(`VaultTemplate.read(…)``VaultTemplate.write(…)`)。

### [](#vault.core.backends.kv1)10.1。键值版本 1(“无版本的秘密”)

`kv`秘密引擎用于在 Vault 配置的物理存储中存储任意秘密。

当以一种非版本管理的方式运行`kv`秘密引擎时,只保留密钥的最近写入的值。无版本 KV 的好处是减少了每个键的存储大小,因为不会存储额外的元数据或历史记录。此外,以这种方式配置到后端的请求性能更好,因为对于任何给定的请求,存储调用更少,也没有锁定。

Spring Vault 附带一个专用的键值 API,以封装各个键值 API 实现之间的差异。`VaultKeyValueOperations`遵循 Vault CLI 的设计。这是 Vault 提供诸如`vault kv get``vault kv put`等命令的主要命令行工具。

通过指定版本和挂载路径,你可以将此 API 用于两个键值引擎版本。下面的示例使用键值版本 1:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
							VaultKeyValueOperationsSupport.KeyValueBackend.KV_1);

keyValueOperations.put("elvis", Collections.singletonMap("password", "409-52-2002"));

VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
```

`VaultKeyValueOperations`支持所有键值操作,如`put``get``delete``list`

或者,可以通过`VaultTemplate`使用该 API,因为其直接映射和简单的使用,因为键和响应直接映射到输入和输出键。下面的示例演示了在`mykey`处写和读一个秘密。`kv`秘密引擎安装在`secret`:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());

operations.write("secret/elvis", Collections.singletonMap("social-security-number", "409-52-2002"));

VaultResponse read = operations.read("secret/elvis");
read.getRequiredData().get("social-security-number");
```

你可以在 Vault 参考文档中找到有关[Vault 键-value 版本 1API](https://www.vaultproject.io/api-docs/secret/kv/kv-v1)的更多详细信息。

### [](#vault.core.backends.kv2)10.2。键值版本 2(“版本管理的秘密”)

你可以在两个版本中的一个版本中运行`kv`秘密引擎。本节使用版本 2 进行说明。当运行版本 2 的`kv`后端时,一个键可以保留可配置的版本数量。你可以检索旧版本的元数据和数据。此外,你还可以使用检查和设置操作来避免无意中覆盖数据。

[键值版本 1(“无版本的秘密”)](#vault.core.backends.kv1)类似, Spring Vault 附带了一个专用的键值 API,以封装各个键值 API 实现之间的差异。 Spring Vault 附带一个专用的键值 API,以封装各个键值 API 实现之间的差异。`VaultKeyValueOperations`遵循 Vault CLI 的设计。这是 Vault 的主要命令行工具,提供诸如`vault kv get``vault kv put`等命令。

通过指定版本和挂载路径,你可以将此 API 用于两个键值引擎版本。下面的示例使用键值版本 2:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultKeyValueOperations keyValueOperations = operations.opsForKeyValue("secret",
							VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);

keyValueOperations.put("elvis", Collections.singletonMap("social-security-number", "409-52-2002"));

VaultResponse read = keyValueOperations.get("elvis");
read.getRequiredData().get("social-security-number");
```

`VaultKeyValueOperations`支持所有键值操作,如`put``get``delete``list`

你还可以与版本管理的键值 API 的具体内容进行交互。如果你想要获得特定的秘密或需要访问元数据,这是非常有用的。

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultVersionedKeyValueOperations versionedOperations = operations.opsForVersionedKeyValue("secret");

Versioned.Metadata metadata = versionedOperations.put("elvis",							(1)
					Collections.singletonMap("social-security-number", "409-52-2002"));

Version version = metadata.getVersion();												(2)

Versioned<Object> ssn = versionedOperations.get("elvis", Version.from(42));				(3)

Versioned<SocialSecurityNumber> mappedSsn = versionedOperations.get("elvis",			(4)
											Version.from(42), SocialSecurityNumber.class);

Versioned<Map<String,String>> versioned = Versioned.create(Collections					(5)
						.singletonMap("social-security-number", "409-52-2002"),
						Version.from(42));

versionedOperations.put("elvis", version);
```

|**1**|将秘密存储在`elvis`上,在`secret/`挂载下可用。|
|-----|---------------------------------------------------------------------------------------------------|
|**2**|将数据存储在版本控制的后端中,将返回元数据,例如版本号。|
|**3**|版本控制的键值 API 允许检索由版本号标识的特定版本。|
|**4**|版本控制的键值秘密可以映射到值对象中。|
|**5**|当使用 CAS 更新受版本控制的秘密时,输入必须引用先前获得的版本。|

而使用`kv`V2Secrets 引擎通过`VaultTemplate`是可能的。这不是最方便的方法,因为 API 提供了一种不同的方法来处理上下文路径以及如何表示输入/输出。具体地说,与实际秘密的交互需要对数据部分进行包装和解包装,并在挂载和秘密密钥之间引入`data/`路径段。

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());

operations.write("secret/data/elvis", Collections.singletonMap("data",
			Collections.singletonMap("social-security-number", "409-52-2002")));

VaultResponse read = operations.read("secret/data/ykey");
Map<String,String> data = (Map<String, String>) read.getRequiredData().get("data");
data.get("social-security-number");
```

你可以在 Vault 参考文档中找到有关[Vault 键-value2API](https://www.vaultproject.io/api-docs/secret/kv/kv-v2)的更多详细信息。

### [](#vault.core.backends.pki)10.3。PKI(公开密钥基础设施)

`pki`Secrets 引擎通过实现证书颁发机构操作来表示证书的后端。

PKI 机密引擎生成动态 X.509 证书。使用这个秘密引擎,服务可以获得证书,而无需经过通常的手工过程,即生成私钥和 CSR,提交给 CA,并等待验证和签名过程完成。Vault 内置的身份验证和授权机制提供了验证功能。

Spring Vault 通过`VaultPkiOperations`支持证书的颁发、签名、撤销和 CRL 检索。所有其他的 PKI 功能都可以通过`VaultOperations`使用。

以下示例简要说明了如何颁发和撤销证书的用法:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultPkiOperations pkiOperations = operations.opsForPki("pki");

VaultCertificateRequest request = VaultCertificateRequest.builder()								(1)
			.ttl(Duration.ofHours(48))
			.altNames(Arrays.asList("prod.dc-1.example.com", "prod.dc-2.example.com"))
			.withIpSubjectAltName("1.2.3.4")
			.commonName("hello.example.com")
			.build();

VaultCertificateResponse response = pkiOperations.issueCertificate("production", request); 		(2)
CertificateBundle certificateBundle = response.getRequiredData();

KeyStore keyStore = certificateBundle.createKeyStore("my-keystore");							(3)

KeySpec privateKey = certificateBundle.getPrivateKeySpec();										(4)
X509Certificate certificate = certificateBundle.getX509Certificate();
X509Certificate caCertificate = certificateBundle.getX509IssuerCertificate();

pkiOperations.revoke(certificateBundle.getSerialNumber());										(5)
```

|**1**|通过使用`VaultCertificateRequest`Builder 构建一个证书请求。|
|-----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|从 Vault 请求证书。<br/>Vault 充当证书颁发机构,并使用签名的 X.509 证书进行响应。<br/>实际响应是`CertificateBundle`。|
|**3**|你可以直接获得生成的证书,作为包含公钥和私钥以及颁发者证书的 Java 密钥存储库。KeyStore 有广泛的用途,这使得这种格式适合于配置(例如,HTTP 客户机、数据库驱动程序或 SSL 安全的 HTTP 服务器)。|
|**4**|`CertificateBundle`允许直接通过 Java Cryptography Extension API 访问私钥以及公共和发行者证书。|
|**5**|一旦一个证书不再使用(或者它已被破坏),你可以通过它的序列号来撤销它。<br/>Vault 在其 CRL 中包含了已撤销的证书。|

你可以在 Vault 参考文档中找到有关[Vault PKI 机密 API](https://www.vaultproject.io/api-docs/secret/pki)的更多详细信息。

### [](#vault.core.backends.token)10.4。令牌认证后端

此后端是不与实际秘密交互的身份验证后端。相反,它提供了访问令牌管理的访问权限。你可以在[认证方法章节](#vault.core.authentication)中阅读有关[基于令牌的身份验证](#vault.authentication.token)的更多信息。

`token`身份验证方法是内置的,并且在`/auth/token`自动可用。它允许用户使用令牌进行身份验证,以及创建新令牌、通过令牌撤销秘密等等。

当任何其他 auth 方法返回一个标识时,Vault Core 调用令牌方法为该标识创建一个新的唯一令牌。

你还可以使用令牌存储来绕过任何其他的 auth 方法。你可以直接创建令牌,也可以对令牌执行各种其他操作,例如更新和撤销。

Spring Vault 使用此后端来更新和撤销由配置的[认证方法](#vault.core.authentication)提供的会话令牌。

以下示例展示了如何从应用程序中请求、更新和撤销 Vault 令牌:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTokenOperations tokenOperations = operations.opsForToken();

VaultTokenResponse tokenResponse = tokenOperations.create();                          (1)
VaultToken justAToken = tokenResponse.getToken();

VaultTokenRequest tokenRequest = VaultTokenRequest.builder().withPolicy("policy-for-myapp")
									.displayName("Access tokens for myapp")
									.renewable()
									.ttl(Duration.ofHours(1))
									.build();

VaultTokenResponse appTokenResponse = tokenOperations.create(tokenRequest);          (2)
VaultToken appToken = appTokenResponse.getToken();

tokenOperations.renew(appToken);                                                     (3)

tokenOperations.revoke(appToken);                                                    (4)
```

|**1**|通过应用角色默认值来创建令牌。|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|使用 Builder API,你可以为要请求的令牌定义细粒度的设置。<br/>请求令牌将返回`VaultToken`,该对象用于 Vault 令牌的值对象。|
|**3**|你可以通过令牌 API 更新令牌。通常,这是通过`SessionManager`来完成的,以保持对保险库会话令牌的跟踪。|
|**4**|如果需要,可以通过令牌 API 撤销令牌。通常,这是通过`SessionManager`来完成的,以保持对保险库会话令牌的跟踪。|

你可以在 Vault 参考文档中找到有关[Vault Token Auth 方法 API](https://www.vaultproject.io/api-docs/auth/token)的更多详细信息。

### [](#vault.core.backends.transit)10.5。传输后端

传输秘密引擎处理传输中数据的加密功能。Vault 不存储发送到这个秘密引擎的数据。它也可以被看作是“加密作为一种服务”或“加密作为一种服务”。Transit Secrets 引擎还可以对数据进行签名和验证,生成数据的散列和 HMAC,并充当随机字节源。

Transit 的主要用例是对来自应用程序的数据进行加密,同时仍将加密的数据存储在一些主数据存储中。这减轻了应用程序开发人员进行适当加密和解密的负担,并将负担推给了 Vault 的运营商。

Spring Vault 支持广泛的中转操作:

* 密钥创建

* 密钥重新配置

* 加密/解密/重新包装

* HMAC 计算

* 签名和签名验证

`transit`中的所有操作都以键为中心。Transit 引擎支持键和[各种关键类型](https://www.vaultproject.io/docs/secrets/transit)的版本控制。请注意,键类型可能会对可以使用的操作施加限制。

以下示例展示了如何创建密钥以及如何对数据进行加密和解密:

```
VaultOperations operations = new VaultTemplate(new VaultEndpoint());
VaultTransitOperations transitOperations = operations.opsForTransit("transit");

transitOperations.createKey("my-aes-key", VaultTransitKeyCreationRequest.ofKeyType("aes128-gcm96"));	(1)

String ciphertext = transitOperations.encrypt("my-aes-key", "plaintext to encrypt");					(2)

String plaintext = transitOperations.decrypt("my-aes-key", ciphertext);									(3)
```

|**1**|首先,我们需要一个以.<br/>开头的键,每个键都需要指定的类型。`aes128-gcm96`支持加密、解密、密钥派生和收敛加密,在此示例中,我们需要对其进行加密和解密。|
|-----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|接下来,我们对包含应该加密的纯文本的`String`进行加密,<br/>输入`String`使用默认的`Charset`将字符串编码为其二进制表示,<br/>请求令牌将返回`VaultToken`,它被用作 Vault 令牌的值对象。<br/>`encrypt`方法返回 base64 编码的密文,通常从`vault:`开始。|
|**3**|要将密文解密为纯文本,请调用`decrypt`方法。<br/>它会解密密文并返回一个`String`,并使用默认字符集对其进行解码。|

前面的示例使用简单的字符串进行加密操作。虽然它是一种简单的方法,但它有 charset 错误配置的风险,并且不是二进制安全的。当纯文本对数据(如图像、压缩数据或二进制数据结构)使用二进制表示时,需要二进制安全性。

要对二进制数据进行加密和解密,请使用`Plaintext``Ciphertext`值对象,这些对象可以保存二进制值:

```
byte [] plaintext = "plaintext to encrypt".getBytes();

Ciphertext ciphertext = transitOperations.encrypt("my-aes-key", Plaintext.of(plaintext));			(1)

Plaintext decrypttedPlaintext = transitOperations.decrypt("my-aes-key", ciphertext);				(2)
```

|**1**|假设密钥`my-aes-key`已经存在,我们正在加密`Plaintext`对象。<br/>作为回报,`encrypt`方法返回一个`Ciphertext`对象。|
|-----|------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|`Ciphertext`对象可以直接用于解密,并返回`Plaintext`对象。|

`Plaintext``Ciphertext`带有一个上下文对象,`VaultTransitContext`。它用于为[收敛加密](https://www.vaultproject.io/docs/secrets/transit#convergent-encryption)提供一个 nonce 值,并为一个上下文值提供一个使用键派生的值。

Transit 允许对纯文本进行签名并验证给定纯文本的签名。符号操作需要一个不对称的密钥,通常使用椭圆曲线加密或 RSA。

|   |签名使用公钥/私钥分割来确保真实性。<br/>签名者使用其私钥创建签名。否则,任何人都可以以你的名义对消息进行签名。<br/>验证者使用公钥部分来验证签名。实际的签名通常是一个散列值。<br/><br/>在内部,散列将使用私钥进行计算和加密,以创建最终签名。验证将解密签名消息,计算它们自己的纯文本散列,并比较两个散列值以检查签名是否有效。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

```
byte [] plaintext = "plaintext to sign".getBytes();

transitOperations.createKey("my-ed25519-key", VaultTransitKeyCreationRequest.ofKeyType("ed25519"));	(1)

Signature signature = transitOperations.sign("my-ed25519-key", Plaintext.of(plaintext));			(2)

boolean valid = transitOperations.verify("my-ed25519-key", Plaintext.of(plaintext), signature);		(3)
```

|**1**|签名需要一个不对称的密钥。你可以使用任何椭圆曲线加密或 RSA 密钥类型。一旦创建了密钥,你就拥有了创建签名的所有先决条件。|
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|为纯文本消息创建签名。返回的`Signature`包含一个使用 base64 字符的 ASCII 安全字符串。|
|**3**|要验证签名,验证需要一个签名对象和纯文本消息。作为返回值,你将得到签名是否有效。|

你可以在 Vault 参考文档中找到有关[Vault Transit 后端](https://www.vaultproject.io/api/secret/transit)的更多详细信息。

## [](#vault.core.reactive.template)11。ReactiveVaultTemplate 简介

本节涵盖了关于使用 Spring Vault 的反应式编程支持的基本信息。

### 11.1.什么是反应式编程?

简单地说,反应式编程是关于非阻塞的应用程序,它们是异步和事件驱动的,并且需要少量线程来垂直扩展(即在 JVM 内),而不是水平扩展(即通过集群)。

反应性应用程序的一个关键方面是反压力的概念,这是一种确保生产者不会压倒消费者的机制。例如,在从数据库扩展到 HTTP 响应的反应性组件的管道中,当 HTTP 连接太慢时,数据存储库也可以减慢速度或完全停止,直到网络容量释放出来。

### 11.2.反应式保险库客户端

Spring Vault 的反应性客户端支持是建立在[可组合身份验证步骤](#vault.authentication.steps)和 Spring 的功能性`WebClient`之上的,通过 Reactor 内蒂 或 Jetty,这两个功能都具有完全非阻塞的、事件驱动的 HTTP 客户端。

它将`VaultTokenSupplier`作为`VaultToken`的供应商公开以验证 HTTP 请求,并将`ReactiveVaultOperations`作为主要入口点。`VaultEndpoint``ClientOptions`[SSL](#vault.client-ssl)的核心配置在各种客户机实现中被重用。

`ReactiveVaultTemplate`位于包`org.springframework.vault.core`中,是 Spring 的 Reactive Vault 支持的中心类,提供了与 Vault 交互的丰富功能集。该模板提供了在 Vault 中读、写和删除数据的方便操作,并提供了域对象和 Vault 数据之间的映射。

|   |一旦配置完成,`ReactiveVaultTemplate`是线程安全的,并且可以在<br/>多个实例中重用。|
|---|--------------------------------------------------------------------------------------------------------|

Vault 文档和域类之间的映射是通过委托给`WebClient`及其编解码器来完成的。

`ReactiveVaultTemplate`类实现了接口`ReactiveVaultOperations`。在尽可能多的情况下,`ReactiveVaultOperations`上的方法是以 Vault API 上可用的方法命名的,以使熟悉 API 和 CLI 的现有 Vault 开发人员熟悉该 API。例如,你将找到诸如“write”、“delete”和“read”之类的方法。设计目标是使 Vault API 的使用和`ReactiveVaultOperations`之间的转换变得尽可能容易。这两个 API 之间的一个主要区别是,`ReactiveVaultOperations`可以传递域对象,而不是 JSON 键-值对。

|   |引用`ReactiveVaultTemplate`实例<br/>上的操作的首选方法是通过其接口`ReactiveVaultOperations`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------|

`ReactiveVaultTemplate`未显式公开的功能你可以使用几种执行回调方法中的一种来访问底层 API。Execute 回调将为你提供对`WebClient`对象的引用。有关更多信息,请参见[执行回调](#vault.core.reactive.executioncallback)一节。

现在,让我们来看看如何在 Spring 容器的上下文中使用 Vault 的示例。

### [](#vault.core.reactive.template.beans)11.3。注册和配置 Spring Vault bean

使用 Spring vault 不需要 Spring 上下文。然而,在托管上下文中注册的`ReactiveVaultTemplate``VaultTokenSupplier`的实例将参与由 Spring IOC 容器提供的[生命周期事件](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference/core.html#beans-factory-nature)。这对于在应用程序关闭时处理活动的 Vault 会话非常有用。你还受益于在应用程序中重用相同的`ReactiveVaultTemplate`实例。

Spring Vault 附带了一个支持配置类,该配置类提供了 Bean 用于在 Spring 上下文中使用的定义。应用程序配置类通常从`AbstractVaultConfiguration`扩展,并且需要提供环境特定的附加细节。

`AbstractVaultConfiguration`扩展需要实现` VaultEndpoint vaultEndpoint()``ClientAuthentication clientAuthentication()`方法。

例 9。使用基于 Java 的 Bean 元数据注册 Spring Vault 对象

```
@Configuration
public class AppConfig extends AbstractReactiveVaultConfiguration {

    /**
     * Specify an endpoint for connecting to Vault.
     */
    @Override
    public VaultEndpoint vaultEndpoint() {
        return new VaultEndpoint();                            (1)
    }

    /**
     * Configure a client authentication.
     * Please consider a more secure authentication method
     * for production use.
     */
    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("…");                   (2)
    }
}
```

|**1**|创建一个新的`VaultEndpoint`,默认情况下指向`https://localhost:8200`。|
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|此示例使用`TokenAuthentication`快速启动。<br/>有关支持的身份验证方法的详细信息,请参见[认证方法](#vault.core.authentication)。|

### [](#vault.core.reactive.template.sessionmanagement)11.4。会话管理

Spring Vault 需要令牌来验证 Vault 请求。有关身份验证的详细信息,请参见[认证方法](#vault.core.authentication)。反应式客户端需要一个非阻塞令牌供应商,其契约定义在`VaultTokenSupplier`中。令牌可以是静态的,也可以通过[声明的身份验证流程](#vault.authentication.steps)获得。Vault 登录不应该发生在每个经过身份验证的 Vault 交互上,但是会话令牌应该在会话上保存。该方面由实现`ReactiveSessionManager`的会话管理器处理,例如`ReactiveLifecycleAwareSessionManager`

### [](#vault.core.reactive.executioncallback)11.5。执行回调

Spring 所有模板类的一个常见设计特征是,所有功能都被路由到一个模板中执行回调方法。这有助于确保执行异常和可能需要的任何资源管理的一致性。虽然在 JDBC 和 JMS 的情况下,这比 Vault 的需要大得多,但它仍然为访问和日志记录的发生提供了一个单一的位置。因此,使用 Execute 回调是访问 Vault API 的首选方式,以执行我们在`ReactiveVaultTemplate`上没有作为方法公开的不常见操作。

下面是执行回调方法的列表。

* `<T> T`**DowithVault**`(Function<WebClient, ? extends T> clientCallback)`组成给定的反应序列`WebClient`,允许在没有会话上下文的情况下与 Vault 进行交互。

* 会话`<T> T`**首次会议**`(Function<WebClient, ? extends T> clientCallback)`组成给定的反应序列`WebClient`,允许在经过身份验证的保险库中进行交互。

下面是一个使用回调来初始化 Vault 的示例:

```
reactiveVaultOperations.doWithVault(webClient -> {

    return webClient.put()
                    .uri("/sys/init")
                    .syncBody(request)
                    .retrieve()
                    .toEntity(VaultInitializationResponse.class);
});
```

## [](#vault.core.propertysupport)12。保险库财产来源支持

保险库可以有许多不同的使用方式。一个特定的用例是使用 Vault 存储加密的属性。 Spring Vault 支持 Vault 作为属性源,以使用 Spring 的[PropertySource 抽象](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference/core.html#beans-property-source-abstraction)获得配置属性。

|   |你可以引用存储在 Vault 中的其他属性源中的属性,或者使用`@Value(…)`的值注入。当引导需要存储在保险库中的数据的 bean 时,需要特别注意。此时必须初始化`VaultPropertySource`才能从 Vault 检索属性。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |Spring 引导/ Spring 云用户可以受益于[Spring Cloud Vault](https://github.com/spring-cloud/spring-cloud-vault-config)<br/>配置集成,该集成在应用程序启动期间初始化各种属性源。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### 12.1.注册`VaultPropertySource`

Spring Vault 提供了一个`VaultPropertySource`以与 Vault 一起使用来获得属性。它使用嵌套的`data`元素公开在 Vault 中存储和加密的属性。

```
ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new VaultPropertySource(vaultTemplate, "secret/my-application"));
```

在上面的代码中,`VaultPropertySource`在搜索中被添加了最高优先级。如果它包含一个 foo` property, it will be detected and returned ahead of any `foo` property in any other `PropertySource`.`mutablePropertySources` 暴露了许多方法,这些方法允许对属性源集进行精确操作。

### 12.2.@VaultPropertySource

`@VaultPropertySource`注释提供了一种方便的声明性机制,用于将`PropertySource`添加到 Spring 的`Environment`中,以便与`@Configuration`类一起使用。

`@VaultPropertySource`采用 vault 路径,如`secret/my-application`,并公开存储在节点`PropertySource`中的数据。`@VaultPropertySource`支持与租赁相关的秘密的租赁续订(即来自`mysql`后端的凭据)和在终端租赁到期时的凭据旋转。默认情况下,租约续订是禁用的。

例 10。存储在保险库中的属性

```
{
  // …

  "data": {
    "database": {
      "password": ...
    },
    "user.name": ...,
  }

  // …
}
```

例 11。声明`@VaultPropertySource`

```
@Configuration
@VaultPropertySource("secret/my-application")
public class AppConfig {

    @Autowired Environment env;

    @Bean
    public TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setUser(env.getProperty("user.name"));
        testBean.setPassword(env.getProperty("database.password"));
        return testBean;
    }
}
```

例 12。声明带有凭据旋转和前缀的`@VaultPropertySource`

```
@Configuration
@VaultPropertySource(value = "aws/creds/s3-access",
                     propertyNamePrefix = "aws.",
                     renewal = Renewal.ROTATE)
public class AppConfig {
  // provides aws.access_key and aws.secret_key properties
}
```

|   |从`generic`秘密后端获得的秘密与 TTL(`refresh_interval`)相关联,但不是租赁 ID。 Spring Vault 的`PropertySource`在到达其 TTL 时会旋转通用秘密。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

|   |你可以使用`@VaultPropertySource`从版本控制的键值后端获得最新的秘密版本。确保路径中不包含`data/`段。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|

在`@VaultPropertySource`路径中存在的任何`${…​}`占位符都将根据已经针对该环境注册的一组属性源进行解析,如下例所示:

例 13。使用占位符声明`@VaultPropertySource`路径

```
@Configuration
@VaultPropertySource(value = "aws/creds/${my.placeholder:fallback/value}",
                     propertyNamePrefix = "aws.",
                     renewal = Renewal.ROTATE)
public class AppConfig {
}
```

假设`my.placeholder`存在于已经注册的一个属性源中(例如,系统属性或环境变量),则将占位符解析为相应的值。如果不是,则将`fallback/value`用作默认值。如果没有指定默认值,并且无法解析某个属性,则抛出一个`IllegalArgumentException`。

在某些情况下,当使用`@VaultPropertySource`注释时,严格控制属性源排序可能是不可能的或不实用的。例如,如果上面的`@Configuration`类是通过组件扫描注册的,那么排序是很难预测的。在这种情况下(如果重写很重要),建议用户回到使用 PropertySource API。详见[`ConfigurableEnvironment`](https://DOCS. Spring.io/ Spring-framework/DOCS/current/javadoc-api/org/springframework/core/core/ENV/confirablebletermnirtonment.html)和[<gtr="527"/>](https://DOCS. Spring.io/ Spring/DOCS/current/javadoc-api/org/springframework/core/env/mutablepropertysources.html))

## [](#vault.repositories)13。保险库

使用`VaultTemplate`和映射到 Java 类的响应可以实现基本的数据操作,如读、写和删除。 Spring Vault 存储库在 Vault 之上应用了数据存储库的概念。Vault 存储库公开了基本的增删改查功能,并支持使用限制 ID 属性、分页和排序的谓词进行查询派生。

|   |在[Spring Data Commons reference documentation](https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories)中阅读有关 Spring 数据存储库的更多信息。参考文档将向你介绍 Spring 数据存储库。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

### [](#vault.repositories.usage)13.1。用法

要访问存储在 Vault 中的域实体,你可以利用存储库支持,从而大大简化这些实现。

例 14。示例凭据实体

```
@Secret
public class Credentials {

  @Id String id;
  String password;
  String socialSecurityNumber;
  Address address;
}
```

这里有一个非常简单的域对象。请注意,它有一个名为`id`的属性,并对其类型进行了`org.springframework.data.annotation.Id`注释和`@Secret`注释。这两个人负责创建用于在 Vault 内部将对象持久化为 JSON 的实际密钥。

|   |用`@Id`注释的属性以及那些名为`id`的属性被视为标识符属性。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------|

下一步是声明一个使用域对象的存储库接口。

例 15。`Credentials`实体的基本存储库接口

```
public interface CredentialsRepository extends CrudRepository<Credentials, String> {

}
```

当我们的存储库扩展`CrudRepository`时,它提供了基本的增删改查和查询方法。保险库需要 Spring 个数据组件。确保在类路径中包含`spring-data-commons`和`spring-data-keyvalue`工件。

要实现这一点,最简单的方法是设置依赖管理,并将工件添加到`pom.xml`:

然后将以下内容添加到`pom.xml`依赖关系部分。

例 16。使用 Spring 数据 BOM

```
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-bom</artifactId>
      <version>2020.0.2</version>
      <scope>import</scope>
      <type>pom</type>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>

  <!-- other dependency elements omitted -->

  <dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
    <version>2.3.1</version>
  </dependency>

  <dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-keyvalue</artifactId>
    <!-- Version inherited from the BOM -->
  </dependency>

</dependencies>
```

我们需要在两者之间将东西粘在一起的东西是根据 Spring 配置的。

例 17。JavaConfig 用于保险库存储库

```
@Configuration
@EnableVaultRepositories
public class ApplicationConfig {

  @Bean
  public VaultTemplate vaultTemplate() {
    return new VaultTemplate(…);
  }
}
```

鉴于上述设置,我们可以继续并注入`CredentialsRepository`到我们的组件。

例 18。访问个人实体

```
@Autowired CredentialsRepository repo;

public void basicCrudOperations() {

  Credentials creds = new Credentials("heisenberg", "327215", "AAA-GG-SSSS");
  rand.setAddress(new Address("308 Negra Arroyo Lane", "Albuquerque", "New Mexico", "87104"));

  repo.save(creds);                                        (1)

  repo.findOne(creds.getId());                             (2)

  repo.count();                                            (3)

  repo.delete(creds);                                      (4)
}
```

|**1**|将`Credentials`的属性以键模式`keyspace/id`、<br/>存储在 Vault Hash 中,在本例中,将`credentials/heisenberg`的属性存储在通用秘密后端中。|
|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|使用提供的 ID 来检索存储在`keyspace/id`的对象。|
|**3**|计算在`Credentials`上由`@Secret`定义的键位*证书*内可用的实体总数。|
|**4**|从保险库中删除给定对象的密钥。|

### [](#vault.repositories.mapping)13.2。对象到 Vault JSON 映射

Vault 存储库使用 JSON 作为交换格式在 Vault 中存储对象。JSON 和实体之间的对象映射是通过`VaultConverter`完成的。转换器读取和写入`SecretDocument`中包含来自`VaultResponse`的主体的`SecretDocument`。从 Vault 读取`VaultResponse`s,并通过 Jackson 将正文反序列化为`Map`的`String`和`Object`。默认的`VaultConverter`实现读取带有嵌套的值`Map`和`List`的`Map`对象,并将这些对象转换为实体,反之亦然。

给定前几节中的`Credentials`类型,默认映射如下:

```
{
  "_class": "org.example.Credentials",                 (1)
  "password", "327215",                                (2)
  "socialSecurityNumber": "AAA-GG-SSSS",
  "address": {                                         (3)
    "street": "308 Negra Arroyo Lane",
    "city": "Albuquerque",
    "state": "New Mexico",
    "zip":"87104"
  }
}
```

|**1**|`_class`属性包含在根级别以及任何嵌套接口或抽象类型上。|
|-----|------------------------------------------------------------------------------------------------------|
|**2**|简单属性值由路径映射。|
|**3**|复杂类型的属性被映射为嵌套对象。|

|   |`@Id`属性必须映射到`String`。|
|---|----------------------------------------------|

|              Type              |样本|                   Mapped Value                    |
|--------------------------------|--------------------------------------------------------|---------------------------------------------------|
| Simple Type  <br/>(eg. String) |string firstname=“walter”;|               firstname = "Walter"                |
|Complex Type  <br/>(eg. Address)|Address=New Address(“308Negra Arroyo Lane”);|  address: { "street": "308 Negra Arroyo Lane" }   |
|   List  <br/>of Simple Type    |list\<String\>nicknames=aslist(“Walt”,“Heisenberg”);|         nicknames: ["walt", "heisenberg"]         |
|    Map  <br/>of Simple Type    |map\<String, Integer\>atts=asmap(“年龄”,51)|                atts : {"age" : 51}                |
|   List  <br/>of Complex Type   |list\<Address\>addresses=aslist(new address("308…|address: [{ "street": "308 Negra Arroyo Lane" }, …]|

你可以通过在`VaultCustomConversions`中注册`Converter`来定制映射行为。这些转换器可以处理从/转换为诸如`LocalDate`和`SecretDocument`之类的类型,而第一个转换器适合于将简单的属性和最后一个复杂的类型转换为它们的 JSON 表示。第二个选项提供对结果`SecretDocument`的完全控制。将对象写入`Vault`将删除内容并重新创建整个条目,因此未映射的数据将丢失。

### [](#vault.repositories.queries)13.3。查询和查询方法

查询方法允许从方法名自动派生简单的查询。Vault 没有查询引擎,但需要直接访问 HTTP 上下文路径。Vault 查询方法将 Vault 的 API 可能性转换为查询。查询方法执行在上下文路径下列出子项,对 ID 应用筛选,可选地使用偏移量/限制限制限制 ID 流,并在获取结果后应用排序。

例 19。样本库查询方法

```
public interface CredentialsRepository extends CrudRepository<Credentials, String> {

  List<Credentials> findByIdStartsWith(String prefix);
}
```

|   |Vault 存储库的查询方法仅支持带有`@Id`属性上的谓词的查询。|
|---|------------------------------------------------------------------------------------------------|

下面是 Vault 支持的关键字的概述。

|              Keyword               |样本|
|------------------------------------|-------------------------------------------------------------|
|       `After`, `GreaterThan`       |`findByIdGreaterThan(String id)`|
|         `GreaterThanEqual`         |`findByIdGreaterThanEqual(String id)`|
|        `Before`, `LessThan`        |`findByIdLessThan(String id)`|
|          `LessThanEqual`           |`findByIdLessThanEqual(String id)`|
|             `Between`              |`findByIdBetween(String from, String to)`|
|                `In`                |`findByIdIn(Collection ids)`|
|              `NotIn`               |`findByIdNotIn(Collection ids)`|
|`Like`, `StartingWith`, `EndingWith`|`findByIdLike(String id)`|
|       `NotLike`, `IsNotLike`       |`findByIdNotLike(String id)`|
|            `Containing`            |`findByFirstnameContaining(String id)`|
|          `NotContaining`           |`findByFirstnameNotContaining(String name)`|
|              `Regex`               |`findByIdRegex(String id)`|
|           `(No keyword)`           |`findById(String name)`|
|               `Not`                |`findByIdNot(String id)`|
|               `And`                |`findByLastnameAndFirstname`|
|                `Or`                |`findByLastnameOrFirstname`|
|            `Is,Equals`             |`findByFirstname`,`findByFirstnameIs`,`findByFirstnameEquals`|
|            `Top,First`             |`findFirst10ByFirstname`,`findTop5ByFirstname`|

#### 13.3.1.分类和分页

查询方法通过在内存中选择从保险库上下文路径检索的子列表 ID 来支持排序和分页。与查询方法谓词不同,排序不限于特定字段。在进行 ID 过滤后,将应用未分页的排序,并从保险库中获取所有产生的秘密。通过这种方式,查询方法只获取作为结果的一部分返回的结果。

使用分页和排序需要在过滤 ID 之前进行秘密获取,这会影响性能。排序和分页保证返回相同的结果,即使 Vault 返回的 ID 的 Natural Order 发生了变化。因此,首先从 Vault 获取所有 ID,然后应用排序,然后进行过滤和偏移/限制。

例 20。分页和排序存储库

```
public interface CredentialsRepository extends PagingAndSortingRepository<Credentials, String> {

  List<Credentials> findTop10ByIdStartsWithOrderBySocialSecurityNumberDesc(String prefix);

  List<Credentials> findByIdStarts(String prefix, Pageable pageRequest);
}
```

## [](#vault.core.client.support)14。客户支持

Spring Vault 支持各种 HTTP 客户端访问 Vault 的 HTTP API。 Spring Vault 使用[`RestTemplate`](https://DOCS. Spring.io/ Spring/DOCS/5.3.4/ Spring-framework-reference/integration.html#rest-resttemplate)作为访问 Vault 的主要接口。专用的客户机支持源自[定制的 SSL 配置](#vault.client-ssl),其作用域仅限于 Spring Vault 的客户机组件。

Spring Vault 支持以下 HTTP 命令式客户端:

* Java 的内置`HttpURLConnection`(默认客户端)

* Apache HTTP 组件

* Netty

* OKHTTP3

Spring Vault 的反应性集成支持以下反应性 HTTP 客户端:

* 反应堆网状结构

* Jetty

使用特定的客户端需要在 Classpath 上可用的相应的依赖关系,因此 Spring Vault 可以使用可用的客户端与 Vault 进行通信。

### 14.1.Java 的内置`HttpURLConnection`

Java 的内置`HttpURLConnection`是开箱即用的,不需要额外的配置。使用`HttpURLConnection`有一个关于 SSL 配置的限制。 Spring Vault 将不适用[定制的 SSL 配置](#vault.client-ssl),因为它将需要对 JVM 进行深度重新配置。这种配置将影响依赖默认 SSL 上下文的所有组件。使用`HttpURLConnection`配置 SSL 设置需要你将这些设置作为系统属性提供。有关更多详细信息,请参见[定制 JSSE](https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#InstallationAndCustomization)。

### 14.2.外部客户

你可以使用外部客户机访问 Vault 的 API。只需向你的项目添加以下依赖项之一。如果使用[Spring Vault’s Dependency BOM](#dependencies),则可以省略版本号。

例 21。 Apache HTTP 组件依赖关系

```
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
</dependency>
```

|   |Apache HttpClient 的[电汇测井](https://hc.apache.org/httpcomponents-client-4.5.x/logging.html)可以通过日志配置来启用。确保不会意外地启用有线日志,因为日志可能会以纯文本的形式暴露应用程序和保险库之间的流量(令牌和秘密)。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

例 22。内蒂依赖

```
<dependency>
  <groupId>io.netty</groupId>
  <artifactId>netty-all</artifactId>
</dependency>
```

例 23。Square OkHTTP3

```
<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
</dependency>
```

例 24。反应堆网状结构

```
<dependency>
  <groupId>io.projectreactor.netty</groupId>
  <artifactId>reactor-netty</artifactId>
</dependency>
```

例 25。 Jetty

```
<dependency>
  <groupId>org.eclipse.jetty</groupId>
  <artifactId>jetty-reactive-httpclient</artifactId>
</dependency>
```

### [](#vault.client-ssl)14.3。Vault 客户端 SSL 配置

通过设置各种属性,可以使用`SslConfiguration`配置 SSL。你可以设置`javax.net.ssl.trustStore`来配置 JVM 范围内的 SSL 设置,也可以设置`SslConfiguration`来仅为 Spring Vault 设置 SSL 设置。

```
SslConfiguration sslConfiguration = SslConfiguration.create(            (1)
		new FileSystemResource("client-cert.jks"), "changeit".toCharArray(),
		new FileSystemResource("truststore.jks"), "changeit".toCharArray());

SslConfiguration.forTrustStore(new FileSystemResource("keystore.jks"),  (2)
                                      "changeit".toCharArray())

SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"),    (3)
                                      "changeit".toCharArray())

SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"),    (4)
                                      "changeit".toCharArray(),
                                      KeyConfiguration.of("key-password".toCharArray(),
                                      "my-key-alias"))
```

|**1**|全配置。|
|-----|-----------------------------------------------------------------------|
|**2**|只配置信任存储区设置。|
|**3**|只配置密钥存储区设置。|
|**4**|只配置密钥存储区设置并提供密钥配置。|

请注意,提供`SslConfiguration`仅在 Apache HTTP 组件或 OKHTTP 客户端位于你的类路径上时才能应用。

SSL 配置还支持 PEM 编码的证书,以替代 Java 密钥存储区。

```
KeyStoreConfiguration keystore = KeyStoreConfiguration
        .of(new ClassPathResource("ca.pem")).withStoreType("PEM");
SslConfiguration configuration = SslConfiguration.forTrustStore(keystore);
```

PEM 文件可以包含一个或多个证书(块`-----BEGIN CERTIFICATE-----`和`-----END CERTIFICATE-----`)。添加到底层`KeyStore`的证书使用完整的主题名称作为别名。

## [](#vault.core.authentication)15。认证方法

不同的组织对安全性和身份验证有不同的要求。Vault 通过提供多种身份验证方法来反映这种需求。 Spring Vault 支持多种身份验证机制。

### 15.1.外部化登录凭据

获得对安全系统的首次访问称为安全引入。任何客户都需要短暂或永久的凭据才能访问 Vault。外部化凭据是保持代码可维护性高的一种很好的模式,但有可能增加披露的风险。

向任何一方披露登录凭据都允许登录到保险库并访问基础角色允许的秘密。选择适当的客户机身份验证并将凭据注入应用程序将受到风险评估的影响。

Spring 的[PropertySource 抽象](https://docs.spring.io/spring/docs/5.3.4/spring-framework-reference/core.html#beans-property-source-abstraction)是将配置保持在应用程序代码之外的一种自然适合。你可以使用系统属性、环境变量或属性文件来存储登录凭据。每种方法都有自己的特性。请记住,可以通过适当的 OS 访问级别来内省命令行和环境属性。

例 26。将`vault.token`外部化到属性文件

```
@PropertySource("configuration.properties")
@Configuration
public class Config extends AbstractVaultConfiguration {

    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication(getEnvironment().getProperty("vault.token"));
    }
}
```

|   |Spring 允许以多种方式获得`Environment`。当使用`VaultPropertySource`时,通过`@Autowired Environment environment`注入将不会提供`Environment`,因为环境 Bean 仍在构建中,并且自动布线在较晚的阶段到来。你的配置类应该实现`ApplicationContextAware`,并从`ApplicationContext`获得`Environment`。|
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

参见[`SecurePropertyUsage.java`](https://github.com/ Spring-projects/ Spring-vault/blob/master/ Spring-vault-core/SRC/test/java/org/springframework/vault/demo/securepropertyusage.java),以获取在组件和其他属性源中引用属性的示例。

### [](#vault.authentication.token)15.2。令牌认证

令牌是在 Vault 中进行身份验证的核心方法。令牌身份验证需要提供一个静态令牌。

|   |令牌身份验证是默认的身份验证方法。<br/>如果令牌被公开为非预期的一方,则它获得对 Vault 的访问权限,并且<br/>可以为预期的客户端访问秘密。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

通常,令牌身份验证用于在外部创建和更新令牌的场景中(例如[HashiCorpVault Service Broker](https://github.com/hashicorp/vault-service-broker))。根据实际的设置,你可能希望也可能不希望令牌更新和撤销。有关 TTL 和令牌撤销的详细信息,请参见[`LifecycleAwareSessionManager`](#vault.authentication.会话)。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication("…");
    }

    // …
}
```

另见:

* [保险库文档:令牌](https://www.vaultproject.io/docs/concepts/tokens.html)

* [Vault 文档:使用令牌身份验证后端](https://www.vaultproject.io/docs/auth/token.html)

### [](#vault.authentication.appid)15.3。APPID 身份验证

|   |Appid 身份验证被 Vault 反对。用[Approle 身份验证](#vault.authentication.approle)代替。|
|---|-----------------------------------------------------------------------------------------------------------------|

Vault 支持[AppId](https://www.vaultproject.io/docs/auth/app-id.html)身份验证,该验证由两个难以猜测的令牌组成。APPID 默认为静态配置的`spring.application.name`。第二个标记是 userid,它是由应用程序决定的一部分,通常与运行时环境相关。IP 地址、MAC 地址或 Docker 容器名称都是很好的例子。 Spring Vault 支持 IP 地址、MAC 地址和静态用户 ID(例如,通过系统属性提供)。IP 和 MAC 地址表示为十六进制编码的 SHA256 散列。

基于 IP 地址的用户 ID 使用本地主机的 IP 地址。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {
        AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
                .appId("myapp")
                .userIdMechanism(new IpAddressUserId())
                .build();

        return new AppIdAuthentication(options, restOperations());
    }

    // …
}
```

从命令行生成 IP 地址 userid 的相应命令是:

```
$ echo -n 192.168.99.1 | sha256sum
```

|   |包括`echo`的换行将导致不同的散列值<br/>,因此请确保包括`-n`标志。|
|---|-------------------------------------------------------------------------------------------------------------|

基于 MAC 地址的用户 ID 从本地主机绑定的设备获得他们的网络设备。该配置还允许指定`network-interface`提示来选择正确的设备。`network-interface`的值是可选的,可以是接口名称或接口索引(基于 0)。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder()
                .appId("myapp")
                .userIdMechanism(new MacAddressUserId())
                .build();

        return new AppIdAuthentication(options, restOperations());
    }

    // …
}
```

从命令行生成 MAC 地址 userid 的相应命令是:

```
$ echo -n 0AFEDE1234AC | sha256sum
```

|   |MAC 地址是大写的,不带冒号。<br/>包括`echo`的换行将导致不同的散列值<br/>,因此请确保包含`-n`标志。|
|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

#### 15.3.1.自定义用户 ID

更高级的方法允许你实现自己的`AppIdUserIdMechanism`。这个类必须位于你的 Classpath 上,并且必须实现`org.springframework.vault.authentication.AppIdUserIdMechanism`接口和`createUserId`方法。 Spring Vault 将在每次使用 APPID 进行身份验证以获得令牌时通过调用来获得用户 ID。

MyuseridMechanism.java

```
public class MyUserIdMechanism implements AppIdUserIdMechanism {

  @Override
  public String createUserId() {

    String userId = …
    return userId;
  }
}
```

另见:[Vault 文档:使用应用程序 ID Auth 后台](https://www.vaultproject.io/docs/auth/app-id.html)

### [](#vault.authentication.approle)15.4。Approle 身份验证

[AppRole](https://www.vaultproject.io/docs/auth/app-id.html)允许机器身份验证,就像不推荐的(自 Vault0.6.1)[APPID 身份验证](#vault.authentication.appid)一样。Approle 身份验证由两个难以猜测的(秘密)令牌组成:ROLEID 和 SECTROTID。

Spring Vault 通过仅提供 ROLEID 或与提供的 secretID 一起提供认证支持,并从 Vault 获取 ROLEID/secretID(具有响应展开的推拉模式)。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
                .roleId(RoleId.provided("…"))
                .secretId(SecretId.wrapped(VaultToken.of("…")))
                .build();

        return new AppRoleAuthentication(options, restOperations());
    }

    // …
}
```

Spring Vault 还支持全拉模式:如果没有提供 Roleid 和 Secretid, Spring Vault 将使用角色名和初始令牌来检索它们。初始令牌可以与 TTL 和使用限制相关联。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        VaultToken initialToken = VaultToken.of("…");
        AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
                .appRole("…")
                .roleId(RoleId.pull(initialToken))
                .secretId(SecretId.pull(initialToken))
                .build();

        return new AppRoleAuthentication(options, restOperations());
    }

    // …
}
```

另见:[Vault 文档:使用 Approle Auth 后端](https://www.vaultproject.io/docs/auth/approle.html)

### [](#vault.authentication.awsec2)15.5。AWS-EC2 身份验证

[aws-ec2](https://www.vaultproject.io/docs/auth/aws-ec2.html)Auth 后端为 AWS EC2 实例提供了一种安全的引入机制,允许自动检索保险库令牌。与大多数 Vault 身份验证后端不同,该后端不需要首次部署或提供安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 AWS 视为受信任的第三方,并使用以密码签名的动态元数据信息来唯一地表示每个 EC2 实例。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {
        return new AwsEc2Authentication(restOperations());
    }

    // …
}
```

在默认情况下,AWS-EC2 身份验证使 Nonce 能够遵循信任第一次使用(Tofu)原则。任何意外获得 PKCS#7 身份元数据访问权限的一方都可以对 Vault 进行身份验证。

在第一次登录期间, Spring Vault 生成一个 Nonce,该 Nonce 存储在实例 ID 旁边的 auth 后端中。重新验证需要发送相同的 nonce。其他任何一方都没有 Nonce,可以在 Vault 中发出警报,以进行进一步的调查。

nonce 保存在内存中,并在应用程序重新启动时丢失。

AWS-EC2 身份验证角色是可选的,并且是 AMI 的默认值。可以通过在`AwsEc2AuthenticationOptions`中设置身份验证角色来配置身份验证角色。

另见:[Vault 文档:使用 AWS-EC2Auth 后端](https://www.vaultproject.io/docs/auth/aws-ec2.html)

### [](#vault.authentication.awsiam)15.6。AWS-IAM 身份验证

[aws](https://www.vaultproject.io/docs/auth/aws.html)Auth 后台允许使用现有的 AWS IAM 凭据进行 Vault 登录。

AWS IAM 身份验证创建一个已签名的 HTTP 请求,该请求由 Vault 执行,以使用 AWS STS方法获得签名者的身份。AWSV4 签名需要 IAM 凭据。

IAM 凭据可以从运行时环境获得,也可以从外部提供。具有分配的 IAM 主体的 AWS-EC2、Lambda 和 ECS 等运行时环境不需要特定于客户机的凭据配置,但可以从其元数据源获得这些凭据。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
                .credentials(new BasicAWSCredentials(…)).build();

        return new AwsIamAuthentication(options, restOperations());
    }

    // …
}
```

例 27。使用 AWS-EC2 实例配置文件作为凭证源

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder()
                .credentialsProvider(InstanceProfileCredentialsProvider.getInstance()).build();

        return new AwsIamAuthentication(options, restOperations());
    }

    // …
}
```

`AwsIamAuthentication`需要 AWS Java SDK 依赖项(`com.amazonaws:aws-java-sdk-core`),因为身份验证实现使用 AWS SDK 类型作为凭据和请求签名。

你可以通过`AwsIamAuthenticationOptions`配置身份验证。

另见:

* [Vault 文档:使用 AWS Auth 后端](https://www.vaultproject.io/docs/auth/aws.html)

* [AWS 文档:STS GetCallerIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html)

### [](#vault.authentication.azuremsi)15.7。Azure(MSI)认证

[azure](https://www.vaultproject.io/docs/auth/azure.html)Auth 后端为 Azure VM 实例提供了一种安全的引入机制,允许自动检索 Vault 令牌。与大多数 Vault 身份验证后端不同,该后端不需要首次部署或提供安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 Azure 视为受信任的第三方,并使用可绑定到 VM 实例的托管服务标识和实例元数据信息。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        AzureMsiAuthenticationOptions options = AzureMsiAuthenticationOptions.builder()
                    .role(…).build();

        return new AzureMsiAuthentication(options, restOperations());
    }

    // …
}
```

Azure 身份验证需要有关 VM 环境的详细信息(订阅 ID、资源组名称、VM 名称)。这些细节可以通过`AzureMsiAuthenticationOptionsBuilder`进行配置。如果不进行配置,`AzureMsiAuthentication`将查询 Azure 的实例元数据服务,以获取这些详细信息。

另见:

* [Vault 文档:使用 Azure Auth 后台](https://www.vaultproject.io/docs/auth/azure.html)

* [Azure 文档:托管服务标识](https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/overview)

### [](#vault.authentication.gcpgce)15.8。GCP-GCE 认证

[gcp](https://www.vaultproject.io/docs/auth/gcp.html)Auth 后端允许 Vault 通过使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭据登录。

GCPGCE(Google 计算引擎)身份验证为服务帐户创建 JSON Web 令牌形式的签名。使用[实例标识](https://cloud.google.com/compute/docs/instances/verifying-instance-identity)从 GCE 元数据服务获得计算引擎实例的 JWT。该 API 创建了一个 JSON Web 令牌,该令牌可用于确认实例标识。

与大多数 Vault 身份验证后端不同,该后端不需要首次部署或提供安全敏感的凭据(令牌、用户名/密码、客户端证书等)。相反,它将 GCP 视为受信任的第三方,并使用加密签名的动态元数据信息,该信息唯一地表示每个 GCP 服务帐户。

你可以通过`GcpComputeAuthenticationOptions`配置身份验证。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        GcpComputeAuthenticationOptions options = GcpComputeAuthenticationOptions.builder()
				.role(…).build();

		GcpComputeAuthentication authentication = new GcpComputeAuthentication(options,
				restOperations());
    }

    // …
}
```

另见:

* [Vault 文档:使用 GCPAuth 后端](https://www.vaultproject.io/docs/auth/gcp.html)

* [GCP 文件:验证实例的身份](https://cloud.google.com/compute/docs/instances/verifying-instance-identity)

### [](#vault.authentication.gcpiam)15.9。GCP-IAM 认证

[gcp](https://www.vaultproject.io/docs/auth/gcp.html)Auth 后端允许 Vault 通过使用现有的 GCP(Google Cloud Platform)IAM 和 GCE 凭据登录。

GCP,IAM 身份验证以 JSON Web 令牌的形式为服务帐户创建签名。通过调用 GCPIAM 的[`projects.serviceAccounts.signJwt`](https://cloud.google.com/iam/reference/rest/v1/projects.serviceaccounts/signjwt)API,可以获得服务帐户的 JWT。调用者针对 GCPIAM 进行身份验证,并由此证明其身份。此保险库后端将 GCP 视为受信任的第三方。

IAM 凭据可以从运行时环境获得,也可以从外部提供,例如 JSON。JSON 是首选的表单,因为它带有调用`projects.serviceAccounts.signJwt`所需的项目 ID 和服务帐户标识符。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        GcpIamAuthenticationOptions options = GcpIamAuthenticationOptions.builder()
				.role(…).credential(GoogleCredentials.getApplicationDefault()).build();

		GcpIamAuthentication authentication = new GcpIamAuthentication(options,
				restOperations());
    }

    // …
}
```

`GcpIamAuthenticationOptions`需要 Google Cloud Java SDK 依赖项(`com.google.apis:google-api-services-iam`和`com.google.auth:google-auth-library-oauth2-http`),因为身份验证实现使用 Google API 进行凭据和 JWT 签名。

你可以通过`GcpIamAuthenticationOptions`配置身份验证。

|   |Google 凭据需要一个 OAuth2 令牌来维护令牌的生命周期。所有 API<br/>都是同步的,因此,`GcpIamAuthentication`不支持`AuthenticationSteps`这是<br/>需要的反应性使用。|
|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

另见:

* [Vault 文档:使用 GCPAuth 后端](https://www.vaultproject.io/docs/auth/gcp.html)

* [GCP 文档:projects.serviceaccounts.signjwt](https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts/signJwt)[]()

### [](#vault.authentication.pcf)15.10。PCF 认证

[pcf](https://www.vaultproject.io/docs/auth/pcf.html)Auth 后端允许对 PCF 实例进行 Vault 登录。它利用[PCF 的应用程序和容器身份保证](https://content.pivotal.io/blog/new-in-pcf-2-1-app-container-identity-assurance-via-automatic-cert-rotation)。

PCF 身份验证使用实例密钥和证书来创建由 Vault 验证的签名。如果签名匹配,并且可能绑定的组织/空间/应用程序 ID 匹配,Vault 将发出一个范围适当的令牌。

实例凭据可从`CF_INSTANCE_CERT`和`CF_INSTANCE_KEY`变量的文件中获得。

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        PcfAuthenticationOptions options = PcfAuthenticationOptions.builder()
                .role(…).build();

        PcfAuthentication authentication = new PcfAuthentication(options,
                restOperations());
    }

    // …
}
```

`PcfAuthenticationOptions`需要[Bouncycastle](https://www.bouncycastle.org/latest_releases.html)库来创建 RSA-PSS 签名。

你可以通过`PcfAuthenticationOptions`配置身份验证。

另见:

* [Vault 文档:使用 PCF Auth 后端](https://www.vaultproject.io/docs/auth/pcf.html)

### [](#vault.authentication.clientcert)15.11。TLS 证书认证

`cert`Auth 后端允许使用 SSL/TLS 客户机证书进行身份验证,这些证书由 CA 签名或自签名。

要启用`cert`身份验证,你需要:

1. 使用 SSL,参见[Vault 客户端 SSL 配置](#vault.client-ssl)

2. 配置包含客户端证书和私钥的 Java`Keystore`

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder()
                .path(…).build();

        return new ClientCertificateAuthentication(options, restOperations());
    }

    // …
}
```

另见:[Vault 文档:使用 CERTAuth 后端](https://www.vaultproject.io/docs/auth/cert.html)

### [](#vault.authentication.cubbyhole)15.12。空穴身份验证

Cubbyhole 身份验证使用 Vault 原语提供安全的身份验证工作流。Cubbyhole 身份验证使用令牌作为主要登录方法。一个短暂的令牌用于从 Vault 的 Cubbyhole 秘密后端获得第二个登录 VaultToken。登录令牌通常寿命更长,并用于与 Vault 交互。可以从包装的响应或`data`部分检索登录令牌。

**创建一个包装好的令牌**

|   |令牌创建的响应包装需要 Vault0.6.0 或更高版本。|
|---|--------------------------------------------------------------------|

例 28。排版和存储令牌

```
$ vault token-create -wrap-ttl="10m"
Key                            Value
---                            -----
wrapping_token:                397ccb93-ff6c-b17b-9389-380b01ca2645
wrapping_token_ttl:            0h10m0s
wrapping_token_creation_time:  2016-09-18 20:29:48.652957077 +0200 CEST
wrapped_accessor:              46b6aebb-187f-932a-26d7-4f3d86a68319
```

例 29。包装的令牌响应用法

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
                .builder()
                .initialToken(VaultToken.of("…"))
                .wrapped()
                .build();

        return new CubbyholeAuthentication(options, restOperations());
    }

    // …
}
```

**使用存储令牌**

例 30。排版和存储令牌

```
$ vault token create
Key                    Value
---                    -----
token                  f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
token_accessor         4eee9bd9-81bb-06d6-af01-723c54a72148
token_duration         0s
token_renewable        false
token_policies         [root]

$ vault token create -use-limit=2 -orphan -no-default-policy -policy=none
Key                    Value
---                    -----
token                  895cb88b-aef4-0e33-ba65-d50007290780
token_accessor         e84b661c-8aa8-2286-b788-f258f30c8325
token_duration         0s
token_renewable        false
token_policies         [none]

$ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780
$ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
```

例 31。存储令牌响应用法

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
                .builder()
                .initialToken(VaultToken.of("…"))
                .path("cubbyhole/token")
                .build();

        return new CubbyholeAuthentication(options, restOperations());
    }

    // …
}
```

**剩余 TTL/可再生性**

在创建令牌时,从与非零 TTL 相关联的 Cubbyhole 检索的令牌开始其 TTL。这个时间不一定与应用程序启动相同。为了补偿初始延迟,Cubbyhole 身份验证对与非零 TTL 相关的令牌执行自查找,以检索剩余的 TTL。在没有 TTL 的情况下,Cubbyhole 身份验证将不会自我查找包装的令牌,因为零 TTL 表示没有关联的 TTL。

非包装令牌不提供有关可更新性和 TTL 的详细信息,只检索令牌。自我查找将查找可再生性和剩余的 TTL。

另见:

* [保险库文档:令牌](https://www.vaultproject.io/docs/concepts/tokens.html)

* [Vault 文档:Cubbyhole 秘密后端](https://www.vaultproject.io/docs/secrets/cubbyhole/index.html)

* [保险库文档:响应包装](https://www.vaultproject.io/docs/concepts/response-wrapping.html)

### [](#vault.authentication.kubernetes)15.13。Kubernetes 认证

Vault 支持使用 Kubernetes 令牌的基于 0.8.3[kubernetes](https://www.vaultproject.io/docs/auth/kubernetes.html)的身份验证。

使用 Kubernetes 身份验证需要一个 Kubernetes 服务帐户令牌,通常挂载在`/var/run/secrets/kubernetes.io/serviceaccount/token`。该文件包含被读取并发送到 Vault 的令牌。Vault 在登录时使用 Kubernetes 的 API 验证其有效性。

配置 Kubernetes 身份验证至少需要提供角色名:

```
@Configuration
class AppConfig extends AbstractVaultConfiguration {

    // …

    @Override
    public ClientAuthentication clientAuthentication() {

        KubernetesAuthenticationOptions options = KubernetesAuthenticationOptions.builder()
                .role(…).jwtSupplier(…).build();

        return new KubernetesAuthentication(options, restOperations());
    }

    // …
}
```

你可以通过`KubernetesAuthenticationOptions`配置身份验证。

另见:

* [Vault 文档:使用 Kubernetes Auth 后台](https://www.vaultproject.io/docs/auth/kubernetes.html)

* [Kubernetes 文档:为 PODS 配置服务帐户](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)

### [](#vault.authentication.steps)15.14。认证步骤

`ClientAuthentication`对象描述身份验证流程并执行实际的身份验证步骤。预先组合的身份验证很容易使用,并通过与同步执行的紧密绑定进行配置。

身份验证方法的组合和重用常见步骤,例如将登录有效负载发布到 Vault 或从 HTTP 源检索身份验证输入,并不打算使用`ClientAuthentication`对象。

身份验证步骤提供了公共身份验证活动的可重用性。通过`AuthenticationSteps`创建的步骤以功能风格描述了一个身份验证流程,将实际的身份验证执行留给了特定的执行者。

例 32。存储令牌验证流.

```
AuthenticationSteps.just(VaultToken.of(…));                              (1)
```

|**1**|仅从`VaultToken`创建`AuthenticationSteps`。|
|-----|-------------------------------------------------------|

可以从单个输入创建单步身份验证流。声明多个身份验证步骤的流以`Supplier`或`HttpRequest`开始,这些流提供了一个身份验证状态对象,可用于将其映射或发布到 Vault 以进行登录。

例 33。Approle 认证流程

```
AuthenticationSteps.fromSupplier(                                       (1)

    () -> getAppRoleLogin(options.getRoleId(), options.getSecretId()))  (2)

    .login("auth/{mount}/login", options.getPath());                    (3)
```

|**1**|开始声明`AuthenticationSteps`接受`Supplier<T>`。<br/>状态对象类型取决于`Supplier`响应类型,该响应类型可以在以后的步骤中映射。|
|-----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|**2**|实际的`Supplier`实现。<br/>在这种情况下创建`Map`。|
|**3**|通过将状态对象(`Map`)发布到 Vault 端点来执行 Vault 登录,以创建 Vault 令牌。<br/>注意,模板变量受 URL 转义的影响。|

身份验证流需要一个执行器来执行实际的登录。我们为不同的执行模型提供了两个执行器:

* `AuthenticationStepsExecutor`作为同步`ClientAuthentication`的插入替换。

* `AuthenticationStepsOperator`用于反应式执行。

许多`ClientAuthentication`都带有静态工厂方法,可以为它们的身份验证特定选项创建`AuthenticationSteps`:

例 34。同步`AuthenticationSteps`执行

```
CubbyholeAuthenticationOptions options = …
RestOperations restOperations = …

AuthenticationSteps steps = CubbyholeAuthentication.createAuthenticationSteps(options);

AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, restOperations);

VaultToken token = executor.login();
```

### [](#vault.authentication.session)15.15。令牌生命周期

Vault 的令牌可以与生存时间相关联。通过身份验证方法获得的令牌旨在在会话处于活动状态时使用,并且在应用程序处于活动状态时不应过期。

Spring Vault 提供了[`LifecycleAwareSessionManager`](https://DOCS. Spring.io/ Spring-vault/DOCS/2.3.1/api/org/springframework/vault/authentication/lifecycleawaresessionmanager.html)会话管理器,它可以更新令牌,直到它到达其终端 TTL,然后执行另一个登录,以获得与会话相关联的下一个令牌。

根据身份验证方法的不同,登录可以创建两种令牌:

* [`VaultToken`](https://DOCS. Spring.io/ Spring-vault/DOCS/2.3.1/api/org/springframework/vault/support/vaulttoken.html):封装实际令牌的通用令牌。

* [`LoginToken`](https://DOCS. Spring.io/ Spring-vault/DOCS/2.3.1/api/org/springframework/vault/support/logintoken.html):与可再生性/ttl 相关联的令牌。

诸如[`TokenAuthentication`](https://DOCS. Spring.io/ Spring-vault/DOCS/2.3.1/api/org/springframework/vault/authentication/tokenauthentication.html)之类的认证方法只需创建一个`VaultToken`,其中不包含任何可再生性/TTL 详细信息。`LifecycleAwareSessionManager`将在令牌上运行自我查找,以从 Vault 检索可更新性和 TTL。如果启用了自我查找,`VaultToken`将定期更新。注意,`VaultToken`永远不会被撤销,只有`LoginToken`才会被撤销。

直接创建`LoginToken`的身份验证方法(所有基于登录的身份验证方法)已经为设置令牌更新提供了所有必要的详细信息。如果会话Manager 被关闭,则`LifecycleAwareSessionManager`将撤销从登录中获得的令牌。

## [](#vault.misc)16。杂项

在本章中学习一些值得一提的细节,比如 Spring 安全集成。

### [](#vault.misc.spring-security)16.1。 Spring 安全

Spring Vault 通过为[`BytesKeyGenerator`](https://DOCS. Spring.io/ Spring-security/site/DOCS/current/reference/htmlsingle/# Spring-security-crypto-keygenerators)和[<<`BytesEncryptor`](https://DOCS. Spring.io/ Spring-security/site/DOCS/current/reference/htmlsingle/# Spring-security-crypto-crypto-cryp 这两种实现都使用 Vault 的`transit`后端。

例 35。`VaultBytesKeyGenerator`示例

```
VaultOperations operations = …;
VaultBytesKeyGenerator generator = new VaultBytesKeyGenerator(operations);

byte[] key = generator.generateKey();
```

例 36。`VaultBytesEncryptor`示例

```
VaultTransitOperations transit = …;

VaultBytesEncryptor encryptor = new VaultBytesEncryptor(transit, "my-key-name");

byte[] ciphertext = encryptor.encrypt(plaintext);

byte[] result = encryptor.decrypt(ciphertext);
```

Vault 封装了一个熵源,该熵源与服务器端密钥管理一起与你的 JVM 分离。这减轻了应用程序开发人员进行适当加密/解密的负担,并将负担推给了 Vault 的运营商。Vault 的操作人员通常包括组织中的安全团队,这意味着他们可以确保数据被正确地加密/解密。此外,由于加密/解密操作必须进入审计日志,因此任何解密事件都会被记录。

后端还支持键旋转,这允许生成指定键的新版本。所有使用该密钥加密的数据都将使用该密钥的最新版本;以前加密的数据可以使用该密钥的旧版本进行解密。管理员可以控制可用于解密的密钥的先前版本,以防止攻击者获得旧的密文副本以成功解密该密钥。

毕竟,Vault 是一种网络服务,每一次操作都会有一个延迟。大量使用加密或随机字节生成的组件可能会在吞吐量和性能方面遇到差异。