"}},"component({\"componentId\":\"custom.widget.Beta_MetaNav\"})":{"__typename":"Component","render({\"context\":{\"component\":{\"entities\":[],\"props\":{}},\"page\":{\"entities\":[],\"name\":\"TagPage\",\"props\":{},\"url\":\"https://community.f5.com\"}}})":{"__typename":"ComponentRenderResult","html":" "}},"tagFollowsForNodes({\"nodeIds\":\"category:top\",\"tagText\":\"series-f5-and-hashicorp-essentials\"})":[{"__typename":"TagFollowForNodeResponse","coreNode":{"__ref":"Category:category:top"},"follow":null}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/community/NavbarDropdownToggle\"]})":[{"__ref":"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/common/OverflowNav\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageView/MessageViewInline\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/users/UserLink\"]})":[{"__ref":"CachedAsset:text:en_US-components/users/UserLink-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageSubject\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageSubject-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageBody\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageBody-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageTime\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageTime-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/nodes/NodeIcon\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageUnreadCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageViewCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageViewCount-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/kudos/KudosCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/kudos/KudosCount-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"components/messages/MessageRepliesCount\"]})":[{"__ref":"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1728320186000"}],"cachedText({\"lastModified\":\"1728320186000\",\"locale\":\"en-US\",\"namespaces\":[\"shared/client/components/users/UserAvatar\"]})":[{"__ref":"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1728320186000"}]},"CachedAsset:pages-1737020669401":{"__typename":"CachedAsset","id":"pages-1737020669401","value":[{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogViewAllPostsPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId/all-posts/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CasePortalPage","type":"CASE_PORTAL","urlPath":"/caseportal","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CreateGroupHubPage","type":"GROUP_HUB","urlPath":"/groups/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CaseViewPage","type":"CASE_DETAILS","urlPath":"/case/:caseId/:caseNumber","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"InboxPage","type":"COMMUNITY","urlPath":"/inbox","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"HelpFAQPage","type":"COMMUNITY","urlPath":"/help","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaMessagePage","type":"IDEA_POST","urlPath":"/idea/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaViewAllIdeasPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/all-ideas/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"LoginPage","type":"USER","urlPath":"/signin","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogPostPage","type":"BLOG","urlPath":"/category/:categoryId/blogs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ThemeEditorPage","type":"COMMUNITY","urlPath":"/designer/themes","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbViewAllArticlesPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId/all-articles/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"OccasionEditPage","type":"EVENT","urlPath":"/event/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"OAuthAuthorizationAllowPage","type":"USER","urlPath":"/auth/authorize/allow","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"PageEditorPage","type":"COMMUNITY","urlPath":"/designer/pages","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"PostPage","type":"COMMUNITY","urlPath":"/category/:categoryId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumBoardPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbBoardPage","type":"TKB","urlPath":"/category/:categoryId/kb/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"EventPostPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"UserBadgesPage","type":"COMMUNITY","urlPath":"/users/:login/:userId/badges","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"GroupHubMembershipAction","type":"GROUP_HUB","urlPath":"/membership/join/:nodeId/:membershipType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaReplyPage","type":"IDEA_REPLY","urlPath":"/idea/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"UserSettingsPage","type":"USER","urlPath":"/mysettings/:userSettingsTab","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"GroupHubsPage","type":"GROUP_HUB","urlPath":"/groups","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumPostPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"OccasionRsvpActionPage","type":"OCCASION","urlPath":"/event/:boardId/:messageSubject/:messageId/rsvp/:responseType","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"VerifyUserEmailPage","type":"USER","urlPath":"/verifyemail/:userId/:verifyEmailToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"AllOccasionsPage","type":"OCCASION","urlPath":"/category/:categoryId/events/:boardId/all-events/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"EventBoardPage","type":"EVENT","urlPath":"/category/:categoryId/events/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbReplyPage","type":"TKB_REPLY","urlPath":"/kb/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaBoardPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CommunityGuideLinesPage","type":"COMMUNITY","urlPath":"/communityguidelines","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CaseCreatePage","type":"SALESFORCE_CASE_CREATION","urlPath":"/caseportal/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbEditPage","type":"TKB","urlPath":"/kb/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForgotPasswordPage","type":"USER","urlPath":"/forgotpassword","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaEditPage","type":"IDEA","urlPath":"/idea/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TagPage","type":"COMMUNITY","urlPath":"/tag/:tagName","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogBoardPage","type":"BLOG","urlPath":"/category/:categoryId/blog/:boardId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"OccasionMessagePage","type":"OCCASION_TOPIC","urlPath":"/event/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ManageContentPage","type":"COMMUNITY","urlPath":"/managecontent","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ClosedMembershipNodeNonMembersPage","type":"GROUP_HUB","urlPath":"/closedgroup/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CommunityPage","type":"COMMUNITY","urlPath":"/","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumMessagePage","type":"FORUM_TOPIC","urlPath":"/discussions/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"IdeaPostPage","type":"IDEA","urlPath":"/category/:categoryId/ideas/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogMessagePage","type":"BLOG_ARTICLE","urlPath":"/blog/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"RegistrationPage","type":"USER","urlPath":"/register","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"EditGroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumEditPage","type":"FORUM","urlPath":"/discussions/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ResetPasswordPage","type":"USER","urlPath":"/resetpassword/:userId/:resetPasswordToken","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbMessagePage","type":"TKB_ARTICLE","urlPath":"/kb/:boardId/:messageSubject/:messageId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogEditPage","type":"BLOG","urlPath":"/blog/:boardId/:messageSubject/:messageId/edit","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ManageUsersPage","type":"USER","urlPath":"/users/manage/:tab?/:manageUsersTab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumReplyPage","type":"FORUM_REPLY","urlPath":"/discussions/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"PrivacyPolicyPage","type":"COMMUNITY","urlPath":"/privacypolicy","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"NotificationPage","type":"COMMUNITY","urlPath":"/notifications","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"UserPage","type":"USER","urlPath":"/users/:login/:userId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"OccasionReplyPage","type":"OCCASION_REPLY","urlPath":"/event/:boardId/:messageSubject/:messageId/comments/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ManageMembersPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/manage/:tab?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"SearchResultsPage","type":"COMMUNITY","urlPath":"/search","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"BlogReplyPage","type":"BLOG_REPLY","urlPath":"/blog/:boardId/:messageSubject/:messageId/replies/:replyId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"GroupHubPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TermsOfServicePage","type":"COMMUNITY","urlPath":"/termsofservice","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"CategoryPage","type":"CATEGORY","urlPath":"/category/:categoryId","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"ForumViewAllTopicsPage","type":"FORUM","urlPath":"/category/:categoryId/discussions/:boardId/all-topics/(/:after|/:before)?","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"TkbPostPage","type":"TKB","urlPath":"/category/:categoryId/kbs/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"},{"lastUpdatedTime":1737020669401,"localOverride":null,"page":{"id":"GroupHubPostPage","type":"GROUP_HUB","urlPath":"/group/:groupHubId/:boardId/create","__typename":"PageDescriptor"},"__typename":"PageResource"}],"localOverride":false},"CachedAsset:text:en_US-components/context/AppContext/AppContextProvider-0":{"__typename":"CachedAsset","id":"text:en_US-components/context/AppContext/AppContextProvider-0","value":{"noCommunity":"Cannot find community","noUser":"Cannot find current user","noNode":"Cannot find node with id {nodeId}","noMessage":"Cannot find message with id {messageId}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-0":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-0","value":{"title":"Loading..."},"localOverride":false},"User:user:-1":{"__typename":"User","id":"user:-1","uid":-1,"login":"Former Member","email":"","avatar":null,"rank":null,"kudosWeight":1,"registrationData":{"__typename":"RegistrationData","status":"ANONYMOUS","registrationTime":null,"confirmEmailStatus":false,"registrationAccessLevel":"VIEW","ssoRegistrationFields":[]},"ssoId":null,"profileSettings":{"__typename":"ProfileSettings","dateDisplayStyle":{"__typename":"InheritableStringSettingWithPossibleValues","key":"layout.friendly_dates_enabled","value":"false","localValue":"true","possibleValues":["true","false"]},"dateDisplayFormat":{"__typename":"InheritableStringSetting","key":"layout.format_pattern_date","value":"dd-MMM-yyyy","localValue":"MM-dd-yyyy"},"language":{"__typename":"InheritableStringSettingWithPossibleValues","key":"profile.language","value":"en-US","localValue":"en","possibleValues":["en-US"]}},"deleted":false},"Theme:customTheme1":{"__typename":"Theme","id":"customTheme1"},"CachedAsset:theme:customTheme1-1737020668971":{"__typename":"CachedAsset","id":"theme:customTheme1-1737020668971","value":{"id":"customTheme1","animation":{"fast":"150ms","normal":"250ms","slow":"500ms","slowest":"750ms","function":"cubic-bezier(0.07, 0.91, 0.51, 1)","__typename":"AnimationThemeSettings"},"avatar":{"borderRadius":"50%","collections":["custom"],"__typename":"AvatarThemeSettings"},"basics":{"browserIcon":{"imageAssetName":"JimmyPackets-512-1702592938213.png","imageLastModified":"1702592945815","__typename":"ThemeAsset"},"customerLogo":{"imageAssetName":"f5_logo_fix-1704824537976.svg","imageLastModified":"1704824540697","__typename":"ThemeAsset"},"maximumWidthOfPageContent":"1600px","oneColumnNarrowWidth":"800px","gridGutterWidthMd":"30px","gridGutterWidthXs":"10px","pageWidthStyle":"WIDTH_OF_PAGE_CONTENT","__typename":"BasicsThemeSettings"},"buttons":{"borderRadiusSm":"5px","borderRadius":"5px","borderRadiusLg":"5px","paddingY":"5px","paddingYLg":"7px","paddingYHero":"var(--lia-bs-btn-padding-y-lg)","paddingX":"12px","paddingXLg":"14px","paddingXHero":"42px","fontStyle":"NORMAL","fontWeight":"400","textTransform":"NONE","disabledOpacity":0.5,"primaryTextColor":"var(--lia-bs-white)","primaryTextHoverColor":"var(--lia-bs-white)","primaryTextActiveColor":"var(--lia-bs-white)","primaryBgColor":"var(--lia-bs-primary)","primaryBgHoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.85))","primaryBgActiveColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) * 0.7))","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","primaryBorderActive":"1px solid transparent","primaryBorderFocus":"1px solid var(--lia-bs-white)","primaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","secondaryTextColor":"var(--lia-bs-gray-900)","secondaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","secondaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","secondaryBgColor":"var(--lia-bs-gray-400)","secondaryBgHoverColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.96))","secondaryBgActiveColor":"hsl(var(--lia-bs-gray-400-h), var(--lia-bs-gray-400-s), calc(var(--lia-bs-gray-400-l) * 0.92))","secondaryBorder":"1px solid transparent","secondaryBorderHover":"1px solid transparent","secondaryBorderActive":"1px solid transparent","secondaryBorderFocus":"1px solid transparent","secondaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","tertiaryTextColor":"var(--lia-bs-gray-900)","tertiaryTextHoverColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.95))","tertiaryTextActiveColor":"hsl(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), calc(var(--lia-bs-gray-900-l) * 0.9))","tertiaryBgColor":"transparent","tertiaryBgHoverColor":"transparent","tertiaryBgActiveColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.04)","tertiaryBorder":"1px solid transparent","tertiaryBorderHover":"1px solid hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","tertiaryBorderActive":"1px solid transparent","tertiaryBorderFocus":"1px solid transparent","tertiaryBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","destructiveTextColor":"var(--lia-bs-danger)","destructiveTextHoverColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.95))","destructiveTextActiveColor":"hsl(var(--lia-bs-danger-h), var(--lia-bs-danger-s), calc(var(--lia-bs-danger-l) * 0.9))","destructiveBgColor":"var(--lia-bs-gray-300)","destructiveBgHoverColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.96))","destructiveBgActiveColor":"hsl(var(--lia-bs-gray-300-h), var(--lia-bs-gray-300-s), calc(var(--lia-bs-gray-300-l) * 0.92))","destructiveBorder":"1px solid transparent","destructiveBorderHover":"1px solid transparent","destructiveBorderActive":"1px solid transparent","destructiveBorderFocus":"1px solid transparent","destructiveBoxShadowFocus":"0 0 0 1px var(--lia-bs-primary), 0 0 0 4px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","__typename":"ButtonsThemeSettings"},"border":{"color":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","mainContent":"NONE","sideContent":"NONE","radiusSm":"3px","radius":"5px","radiusLg":"9px","radius50":"100vw","__typename":"BorderThemeSettings"},"boxShadow":{"xs":"0 0 0 1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08), 0 3px 0 -1px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.08)","sm":"0 2px 4px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.06)","md":"0 5px 15px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","lg":"0 10px 30px hsla(var(--lia-bs-gray-900-h), var(--lia-bs-gray-900-s), var(--lia-bs-gray-900-l), 0.15)","__typename":"BoxShadowThemeSettings"},"cards":{"bgColor":"var(--lia-panel-bg-color)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":"var(--lia-box-shadow-xs)","__typename":"CardsThemeSettings"},"chip":{"maxWidth":"300px","height":"30px","__typename":"ChipThemeSettings"},"coreTypes":{"defaultMessageLinkColor":"var(--lia-bs-primary)","defaultMessageLinkDecoration":"none","defaultMessageLinkFontStyle":"NORMAL","defaultMessageLinkFontWeight":"400","defaultMessageFontStyle":"NORMAL","defaultMessageFontWeight":"400","forumColor":"#0C5C8D","forumFontFamily":"var(--lia-bs-font-family-base)","forumFontWeight":"var(--lia-default-message-font-weight)","forumLineHeight":"var(--lia-bs-line-height-base)","forumFontStyle":"var(--lia-default-message-font-style)","forumMessageLinkColor":"var(--lia-default-message-link-color)","forumMessageLinkDecoration":"var(--lia-default-message-link-decoration)","forumMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","forumMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","forumSolvedColor":"#62C026","blogColor":"#730015","blogFontFamily":"var(--lia-bs-font-family-base)","blogFontWeight":"var(--lia-default-message-font-weight)","blogLineHeight":"1.75","blogFontStyle":"var(--lia-default-message-font-style)","blogMessageLinkColor":"var(--lia-default-message-link-color)","blogMessageLinkDecoration":"var(--lia-default-message-link-decoration)","blogMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","blogMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","tkbColor":"#C20025","tkbFontFamily":"var(--lia-bs-font-family-base)","tkbFontWeight":"var(--lia-default-message-font-weight)","tkbLineHeight":"1.75","tkbFontStyle":"var(--lia-default-message-font-style)","tkbMessageLinkColor":"var(--lia-default-message-link-color)","tkbMessageLinkDecoration":"var(--lia-default-message-link-decoration)","tkbMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","tkbMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaColor":"#4099E2","qandaFontFamily":"var(--lia-bs-font-family-base)","qandaFontWeight":"var(--lia-default-message-font-weight)","qandaLineHeight":"var(--lia-bs-line-height-base)","qandaFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkColor":"var(--lia-default-message-link-color)","qandaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","qandaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","qandaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","qandaSolvedColor":"#3FA023","ideaColor":"#F3704B","ideaFontFamily":"var(--lia-bs-font-family-base)","ideaFontWeight":"var(--lia-default-message-font-weight)","ideaLineHeight":"var(--lia-bs-line-height-base)","ideaFontStyle":"var(--lia-default-message-font-style)","ideaMessageLinkColor":"var(--lia-default-message-link-color)","ideaMessageLinkDecoration":"var(--lia-default-message-link-decoration)","ideaMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","ideaMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","contestColor":"#FCC845","contestFontFamily":"var(--lia-bs-font-family-base)","contestFontWeight":"var(--lia-default-message-font-weight)","contestLineHeight":"var(--lia-bs-line-height-base)","contestFontStyle":"var(--lia-default-message-link-font-style)","contestMessageLinkColor":"var(--lia-default-message-link-color)","contestMessageLinkDecoration":"var(--lia-default-message-link-decoration)","contestMessageLinkFontStyle":"ITALIC","contestMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","occasionColor":"#EE4B5B","occasionFontFamily":"var(--lia-bs-font-family-base)","occasionFontWeight":"var(--lia-default-message-font-weight)","occasionLineHeight":"var(--lia-bs-line-height-base)","occasionFontStyle":"var(--lia-default-message-font-style)","occasionMessageLinkColor":"var(--lia-default-message-link-color)","occasionMessageLinkDecoration":"var(--lia-default-message-link-decoration)","occasionMessageLinkFontStyle":"var(--lia-default-message-link-font-style)","occasionMessageLinkFontWeight":"var(--lia-default-message-link-font-weight)","grouphubColor":"#491B62","categoryColor":"#949494","communityColor":"#FFFFFF","productColor":"#949494","__typename":"CoreTypesThemeSettings"},"colors":{"black":"#000000","white":"#FFFFFF","gray100":"#F7F7F7","gray200":"#F7F7F7","gray300":"#E8E8E8","gray400":"#D9D9D9","gray500":"#CCCCCC","gray600":"#949494","gray700":"#707070","gray800":"#545454","gray900":"#333333","dark":"#545454","light":"#F7F7F7","primary":"#0C5C8D","secondary":"#333333","bodyText":"#222222","bodyBg":"#F5F5F5","info":"#1D9CD3","success":"#62C026","warning":"#FFD651","danger":"#C20025","alertSystem":"#FF6600","textMuted":"#707070","highlight":"#FFFCAD","outline":"var(--lia-bs-primary)","custom":["#C20025","#081B85","#009639","#B3C6D7","#7CC0EB","#F29A36"],"__typename":"ColorsThemeSettings"},"divider":{"size":"3px","marginLeft":"4px","marginRight":"4px","borderRadius":"50%","bgColor":"var(--lia-bs-gray-600)","bgColorActive":"var(--lia-bs-gray-600)","__typename":"DividerThemeSettings"},"dropdown":{"fontSize":"var(--lia-bs-font-size-sm)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius-sm)","dividerBg":"var(--lia-bs-gray-300)","itemPaddingY":"5px","itemPaddingX":"20px","headerColor":"var(--lia-bs-gray-700)","__typename":"DropdownThemeSettings"},"email":{"link":{"color":"#0069D4","hoverColor":"#0061c2","decoration":"none","hoverDecoration":"underline","__typename":"EmailLinkSettings"},"border":{"color":"#e4e4e4","__typename":"EmailBorderSettings"},"buttons":{"borderRadiusLg":"5px","paddingXLg":"16px","paddingYLg":"7px","fontWeight":"700","primaryTextColor":"#ffffff","primaryTextHoverColor":"#ffffff","primaryBgColor":"#0069D4","primaryBgHoverColor":"#005cb8","primaryBorder":"1px solid transparent","primaryBorderHover":"1px solid transparent","__typename":"EmailButtonsSettings"},"panel":{"borderRadius":"5px","borderColor":"#e4e4e4","__typename":"EmailPanelSettings"},"__typename":"EmailThemeSettings"},"emoji":{"skinToneDefault":"#ffcd43","skinToneLight":"#fae3c5","skinToneMediumLight":"#e2cfa5","skinToneMedium":"#daa478","skinToneMediumDark":"#a78058","skinToneDark":"#5e4d43","__typename":"EmojiThemeSettings"},"heading":{"color":"var(--lia-bs-body-color)","fontFamily":"Inter","fontStyle":"NORMAL","fontWeight":"600","h1FontSize":"30px","h2FontSize":"25px","h3FontSize":"20px","h4FontSize":"18px","h5FontSize":"16px","h6FontSize":"16px","lineHeight":"1.2","subHeaderFontSize":"11px","subHeaderFontWeight":"500","h1LetterSpacing":"normal","h2LetterSpacing":"normal","h3LetterSpacing":"normal","h4LetterSpacing":"normal","h5LetterSpacing":"normal","h6LetterSpacing":"normal","subHeaderLetterSpacing":"2px","h1FontWeight":null,"h2FontWeight":null,"h3FontWeight":null,"h4FontWeight":null,"h5FontWeight":null,"h6FontWeight":null,"__typename":"HeadingThemeSettings"},"icons":{"size10":"10px","size12":"12px","size14":"14px","size16":"16px","size20":"20px","size24":"24px","size30":"30px","size40":"40px","size50":"50px","size60":"60px","size80":"80px","size120":"120px","size160":"160px","__typename":"IconsThemeSettings"},"imagePreview":{"bgColor":"var(--lia-bs-gray-900)","titleColor":"var(--lia-bs-white)","controlColor":"var(--lia-bs-white)","controlBgColor":"var(--lia-bs-gray-800)","__typename":"ImagePreviewThemeSettings"},"input":{"borderColor":"var(--lia-bs-gray-600)","disabledColor":"var(--lia-bs-gray-600)","focusBorderColor":"var(--lia-bs-primary)","labelMarginBottom":"10px","btnFontSize":"var(--lia-bs-font-size-sm)","focusBoxShadow":"0 0 0 3px hsla(var(--lia-bs-primary-h), var(--lia-bs-primary-s), var(--lia-bs-primary-l), 0.2)","checkLabelMarginBottom":"2px","checkboxBorderRadius":"3px","borderRadiusSm":"var(--lia-bs-border-radius-sm)","borderRadius":"var(--lia-bs-border-radius)","borderRadiusLg":"var(--lia-bs-border-radius-lg)","formTextMarginTop":"4px","textAreaBorderRadius":"var(--lia-bs-border-radius)","activeFillColor":"var(--lia-bs-primary)","__typename":"InputThemeSettings"},"loading":{"dotDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.2)","dotLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.5)","barDarkColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.06)","barLightColor":"hsla(var(--lia-bs-white-h), var(--lia-bs-white-s), var(--lia-bs-white-l), 0.4)","__typename":"LoadingThemeSettings"},"link":{"color":"var(--lia-bs-primary)","hoverColor":"hsl(var(--lia-bs-primary-h), var(--lia-bs-primary-s), calc(var(--lia-bs-primary-l) - 10%))","decoration":"none","hoverDecoration":"underline","__typename":"LinkThemeSettings"},"listGroup":{"itemPaddingY":"15px","itemPaddingX":"15px","borderColor":"var(--lia-bs-gray-300)","__typename":"ListGroupThemeSettings"},"modal":{"contentTextColor":"var(--lia-bs-body-color)","contentBg":"var(--lia-bs-white)","backgroundBg":"var(--lia-bs-black)","smSize":"440px","mdSize":"760px","lgSize":"1080px","backdropOpacity":0.3,"contentBoxShadowXs":"var(--lia-bs-box-shadow-sm)","contentBoxShadow":"var(--lia-bs-box-shadow)","headerFontWeight":"700","__typename":"ModalThemeSettings"},"navbar":{"position":"FIXED","background":{"attachment":null,"clip":null,"color":"var(--lia-bs-white)","imageAssetName":null,"imageLastModified":"0","origin":null,"position":"CENTER_CENTER","repeat":"NO_REPEAT","size":"COVER","__typename":"BackgroundProps"},"backgroundOpacity":0.8,"paddingTop":"15px","paddingBottom":"15px","borderBottom":"1px solid var(--lia-bs-border-color)","boxShadow":"var(--lia-bs-box-shadow-sm)","brandMarginRight":"30px","brandMarginRightSm":"10px","brandLogoHeight":"30px","linkGap":"10px","linkJustifyContent":"flex-start","linkPaddingY":"5px","linkPaddingX":"10px","linkDropdownPaddingY":"9px","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkColor":"var(--lia-bs-body-color)","linkHoverColor":"var(--lia-bs-primary)","linkFontSize":"var(--lia-bs-font-size-sm)","linkFontStyle":"NORMAL","linkFontWeight":"400","linkTextTransform":"NONE","linkLetterSpacing":"normal","linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkBgColor":"transparent","linkBgHoverColor":"transparent","linkBorder":"none","linkBorderHover":"none","linkBoxShadow":"none","linkBoxShadowHover":"none","linkTextBorderBottom":"none","linkTextBorderBottomHover":"none","dropdownPaddingTop":"10px","dropdownPaddingBottom":"15px","dropdownPaddingX":"10px","dropdownMenuOffset":"2px","dropdownDividerMarginTop":"10px","dropdownDividerMarginBottom":"10px","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","controllerIconColor":"var(--lia-bs-body-color)","controllerIconHoverColor":"var(--lia-bs-body-color)","controllerTextColor":"var(--lia-nav-controller-icon-color)","controllerTextHoverColor":"var(--lia-nav-controller-icon-hover-color)","controllerHighlightColor":"hsla(30, 100%, 50%)","controllerHighlightTextColor":"var(--lia-yiq-light)","controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerColor":"var(--lia-nav-controller-icon-color)","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","hamburgerBgColor":"transparent","hamburgerBgHoverColor":"transparent","hamburgerBorder":"none","hamburgerBorderHover":"none","collapseMenuMarginLeft":"20px","collapseMenuDividerBg":"var(--lia-nav-link-color)","collapseMenuDividerOpacity":0.16,"__typename":"NavbarThemeSettings"},"pager":{"textColor":"var(--lia-bs-link-color)","textFontWeight":"var(--lia-font-weight-md)","textFontSize":"var(--lia-bs-font-size-sm)","__typename":"PagerThemeSettings"},"panel":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-bs-border-radius)","borderColor":"var(--lia-bs-border-color)","boxShadow":"none","__typename":"PanelThemeSettings"},"popover":{"arrowHeight":"8px","arrowWidth":"16px","maxWidth":"300px","minWidth":"100px","headerBg":"var(--lia-bs-white)","borderColor":"var(--lia-bs-border-color)","borderRadius":"var(--lia-bs-border-radius)","boxShadow":"0 0.5rem 1rem hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.15)","__typename":"PopoverThemeSettings"},"prism":{"color":"#000000","bgColor":"#f5f2f0","fontFamily":"var(--font-family-monospace)","fontSize":"var(--lia-bs-font-size-base)","fontWeightBold":"var(--lia-bs-font-weight-bold)","fontStyleItalic":"italic","tabSize":2,"highlightColor":"#b3d4fc","commentColor":"#62707e","punctuationColor":"#6f6f6f","namespaceOpacity":"0.7","propColor":"#990055","selectorColor":"#517a00","operatorColor":"#906736","operatorBgColor":"hsla(0, 0%, 100%, 0.5)","keywordColor":"#0076a9","functionColor":"#d3284b","variableColor":"#c14700","__typename":"PrismThemeSettings"},"rte":{"bgColor":"var(--lia-bs-white)","borderRadius":"var(--lia-panel-border-radius)","boxShadow":" var(--lia-panel-box-shadow)","customColor1":"#bfedd2","customColor2":"#fbeeb8","customColor3":"#f8cac6","customColor4":"#eccafa","customColor5":"#c2e0f4","customColor6":"#2dc26b","customColor7":"#f1c40f","customColor8":"#e03e2d","customColor9":"#b96ad9","customColor10":"#3598db","customColor11":"#169179","customColor12":"#e67e23","customColor13":"#ba372a","customColor14":"#843fa1","customColor15":"#236fa1","customColor16":"#ecf0f1","customColor17":"#ced4d9","customColor18":"#95a5a6","customColor19":"#7e8c8d","customColor20":"#34495e","customColor21":"#000000","customColor22":"#ffffff","defaultMessageHeaderMarginTop":"14px","defaultMessageHeaderMarginBottom":"10px","defaultMessageItemMarginTop":"0","defaultMessageItemMarginBottom":"10px","diffAddedColor":"hsla(170, 53%, 51%, 0.4)","diffChangedColor":"hsla(43, 97%, 63%, 0.4)","diffNoneColor":"hsla(0, 0%, 80%, 0.4)","diffRemovedColor":"hsla(9, 74%, 47%, 0.4)","specialMessageHeaderMarginTop":"14px","specialMessageHeaderMarginBottom":"10px","specialMessageItemMarginTop":"0","specialMessageItemMarginBottom":"10px","__typename":"RteThemeSettings"},"tags":{"bgColor":"var(--lia-bs-gray-200)","bgHoverColor":"var(--lia-bs-gray-400)","borderRadius":"var(--lia-bs-border-radius-sm)","color":"var(--lia-bs-body-color)","hoverColor":"var(--lia-bs-body-color)","fontWeight":"var(--lia-font-weight-md)","fontSize":"var(--lia-font-size-xxs)","textTransform":"UPPERCASE","letterSpacing":"0.5px","__typename":"TagsThemeSettings"},"toasts":{"borderRadius":"var(--lia-bs-border-radius)","paddingX":"12px","__typename":"ToastsThemeSettings"},"typography":{"fontFamilyBase":"Atkinson Hyperlegible","fontStyleBase":"NORMAL","fontWeightBase":"400","fontWeightLight":"300","fontWeightNormal":"400","fontWeightMd":"500","fontWeightBold":"700","letterSpacingSm":"normal","letterSpacingXs":"normal","lineHeightBase":"1.3","fontSizeBase":"15px","fontSizeXxs":"11px","fontSizeXs":"12px","fontSizeSm":"13px","fontSizeLg":"20px","fontSizeXl":"24px","smallFontSize":"14px","customFonts":[],"__typename":"TypographyThemeSettings"},"unstyledListItem":{"marginBottomSm":"5px","marginBottomMd":"10px","marginBottomLg":"15px","marginBottomXl":"20px","marginBottomXxl":"25px","__typename":"UnstyledListItemThemeSettings"},"yiq":{"light":"#ffffff","dark":"#000000","__typename":"YiqThemeSettings"},"colorLightness":{"primaryDark":0.36,"primaryLight":0.74,"primaryLighter":0.89,"primaryLightest":0.95,"infoDark":0.39,"infoLight":0.72,"infoLighter":0.85,"infoLightest":0.93,"successDark":0.24,"successLight":0.62,"successLighter":0.8,"successLightest":0.91,"warningDark":0.39,"warningLight":0.68,"warningLighter":0.84,"warningLightest":0.93,"dangerDark":0.41,"dangerLight":0.72,"dangerLighter":0.89,"dangerLightest":0.95,"__typename":"ColorLightnessThemeSettings"},"localOverride":false,"__typename":"Theme"},"localOverride":false},"CachedAsset:text:en_US-components/common/EmailVerification-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/common/EmailVerification-1728320186000","value":{"email.verification.title":"Email Verification Required","email.verification.message.update.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. To change your email, visit My Settings.","email.verification.message.resend.email":"To participate in the community, you must first verify your email address. The verification email was sent to {email}. Resend email."},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/Loading/LoadingDot-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/Loading/LoadingDot-1728320186000","value":{"title":"Loading..."},"localOverride":false},"CachedAsset:text:en_US-pages/tags/TagPage-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-pages/tags/TagPage-1728320186000","value":{"tagPageTitle":"Tag:\"{tagName}\" | {communityTitle}","tagPageForNodeTitle":"Tag:\"{tagName}\" in \"{title}\" | {communityTitle}","name":"Tags Page","tag":"Tag: {tagName}"},"localOverride":false},"CachedAsset:quilt:f5.prod:pages/tags/TagPage:community:zihoc95639-1737020667215":{"__typename":"CachedAsset","id":"quilt:f5.prod:pages/tags/TagPage:community:zihoc95639-1737020667215","value":{"id":"TagPage","container":{"id":"Common","headerProps":{"removeComponents":["community.widget.bannerWidget"],"__typename":"QuiltContainerSectionProps"},"items":[{"id":"tag-header-widget","layout":"ONE_COLUMN","bgColor":"var(--lia-bs-white)","showBorder":"BOTTOM","sectionEditLevel":"LOCKED","columnMap":{"main":[{"id":"tags.widget.TagsHeaderWidget","__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"},{"id":"messages-list-for-tag-widget","layout":"ONE_COLUMN","columnMap":{"main":[{"id":"messages.widget.messageListForNodeByRecentActivityWidget","props":{"viewVariant":{"type":"inline","props":{"useUnreadCount":true,"useViewCount":true,"useAuthorLogin":true,"clampBodyLines":3,"useAvatar":true,"useBoardIcon":false,"useKudosCount":true,"usePreviewMedia":true,"useTags":false,"useNode":true,"useNodeLink":true,"useTextBody":true,"truncateBodyLength":-1,"useBody":true,"useRepliesCount":true,"useSolvedBadge":true,"timeStampType":"conversation.lastPostingActivityTime","useMessageTimeLink":true,"clampSubjectLines":2}},"panelType":"divider","useTitle":false,"hideIfEmpty":false,"pagerVariant":{"type":"loadMore"},"style":"list","showTabs":true,"tabItemMap":{"default":{"mostRecent":true,"mostRecentUserContent":false,"newest":false},"additional":{"mostKudoed":true,"mostViewed":true,"mostReplies":false,"noReplies":false,"noSolutions":false,"solutions":false}}},"__typename":"QuiltComponent"}],"__typename":"OneSectionColumns"},"__typename":"OneColumnQuiltSection"}],"__typename":"QuiltContainer"},"__typename":"Quilt"},"localOverride":false},"CachedAsset:quiltWrapper:f5.prod:Common:1737020614134":{"__typename":"CachedAsset","id":"quiltWrapper:f5.prod:Common:1737020614134","value":{"id":"Common","header":{"backgroundImageProps":{"assetName":"header.jpg","backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"LEFT_CENTER","lastModified":"1702932449000","__typename":"BackgroundImageProps"},"backgroundColor":"transparent","items":[{"id":"custom.widget.Beta_MetaNav","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"community.widget.navbarWidget","props":{"showUserName":false,"showRegisterLink":true,"style":{"boxShadow":"var(--lia-bs-box-shadow-sm)","linkFontWeight":"700","controllerHighlightColor":"hsla(30, 100%, 50%)","dropdownDividerMarginBottom":"10px","hamburgerBorderHover":"none","linkFontSize":"15px","linkBoxShadowHover":"none","backgroundOpacity":0.4,"controllerBorderRadius":"var(--lia-border-radius-50)","hamburgerBgColor":"transparent","linkTextBorderBottom":"none","hamburgerColor":"var(--lia-nav-controller-icon-color)","brandLogoHeight":"48px","linkLetterSpacing":"normal","linkBgHoverColor":"transparent","collapseMenuDividerOpacity":0.16,"paddingBottom":"10px","dropdownPaddingBottom":"15px","dropdownMenuOffset":"2px","hamburgerBgHoverColor":"transparent","borderBottom":"0","hamburgerBorder":"none","dropdownPaddingX":"10px","brandMarginRightSm":"10px","linkBoxShadow":"none","linkJustifyContent":"center","linkColor":"var(--lia-bs-primary)","collapseMenuDividerBg":"var(--lia-nav-link-color)","dropdownPaddingTop":"10px","controllerHighlightTextColor":"var(--lia-yiq-dark)","background":{"imageAssetName":"","color":"var(--lia-bs-white)","size":"COVER","repeat":"NO_REPEAT","position":"CENTER_CENTER","imageLastModified":""},"linkBorderRadius":"var(--lia-bs-border-radius-sm)","linkHoverColor":"var(--lia-bs-primary)","position":"FIXED","linkBorder":"none","linkTextBorderBottomHover":"2px solid #0C5C8D","brandMarginRight":"30px","hamburgerHoverColor":"var(--lia-nav-controller-icon-color)","linkBorderHover":"none","collapseMenuMarginLeft":"20px","linkFontStyle":"NORMAL","linkPaddingX":"10px","paddingTop":"10px","linkPaddingY":"5px","linkTextTransform":"NONE","dropdownBorderColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.08)","controllerBgHoverColor":"hsla(var(--lia-bs-black-h), var(--lia-bs-black-s), var(--lia-bs-black-l), 0.1)","linkDropdownPaddingX":"var(--lia-nav-link-px)","linkBgColor":"transparent","linkDropdownPaddingY":"9px","controllerIconColor":"#0C5C8D","dropdownDividerMarginTop":"10px","linkGap":"10px","controllerIconHoverColor":"#0C5C8D"},"links":{"sideLinks":[],"mainLinks":[{"children":[{"linkType":"INTERNAL","id":"migrated-link-1","params":{"boardId":"TechnicalForum","categoryId":"Forums"},"routeName":"ForumBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-2","params":{"boardId":"WaterCooler","categoryId":"Forums"},"routeName":"ForumBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-0","params":{"categoryId":"Forums"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-4","params":{"boardId":"codeshare","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-5","params":{"boardId":"communityarticles","categoryId":"CrowdSRC"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-3","params":{"categoryId":"CrowdSRC"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-7","params":{"boardId":"TechnicalArticles","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"article-series","params":{"boardId":"article-series","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"security-insights","params":{"boardId":"security-insights","categoryId":"Articles"},"routeName":"TkbBoardPage"},{"linkType":"INTERNAL","id":"migrated-link-8","params":{"boardId":"DevCentralNews","categoryId":"Articles"},"routeName":"TkbBoardPage"}],"linkType":"INTERNAL","id":"migrated-link-6","params":{"categoryId":"Articles"},"routeName":"CategoryPage"},{"children":[{"linkType":"INTERNAL","id":"migrated-link-10","params":{"categoryId":"CommunityGroups"},"routeName":"CategoryPage"},{"linkType":"INTERNAL","id":"migrated-link-11","params":{"categoryId":"F5-Groups"},"routeName":"CategoryPage"}],"linkType":"INTERNAL","id":"migrated-link-9","params":{"categoryId":"GroupsCategory"},"routeName":"CategoryPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-12","params":{"boardId":"Events","categoryId":"top"},"routeName":"EventBoardPage"},{"children":[],"linkType":"INTERNAL","id":"migrated-link-13","params":{"boardId":"Suggestions","categoryId":"top"},"routeName":"IdeaBoardPage"}]},"className":"QuiltComponent_lia-component-edit-mode__lQ9Z6","showSearchIcon":false},"__typename":"QuiltComponent"},{"id":"community.widget.bannerWidget","props":{"backgroundColor":"transparent","visualEffects":{"showBottomBorder":false},"backgroundImageProps":{"backgroundSize":"COVER","backgroundPosition":"CENTER_CENTER","backgroundRepeat":"NO_REPEAT"},"fontColor":"#222222"},"__typename":"QuiltComponent"},{"id":"community.widget.breadcrumbWidget","props":{"backgroundColor":"var(--lia-bs-primary)","linkHighlightColor":"#FFFFFF","visualEffects":{"showBottomBorder":false},"backgroundOpacity":60,"linkTextColor":"#FFFFFF"},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"footer":{"backgroundImageProps":{"assetName":null,"backgroundSize":"COVER","backgroundRepeat":"NO_REPEAT","backgroundPosition":"CENTER_CENTER","lastModified":null,"__typename":"BackgroundImageProps"},"backgroundColor":"var(--lia-bs-body-color)","items":[{"id":"custom.widget.Beta_Footer","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Tag_Manager_Helper","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"},{"id":"custom.widget.Consent_Blackbar","props":{"widgetVisibility":"signedInOrAnonymous","useTitle":true,"useBackground":false,"title":"","lazyLoad":false},"__typename":"QuiltComponent"}],"__typename":"QuiltWrapperSection"},"__typename":"QuiltWrapper","localOverride":false},"localOverride":false},"CachedAsset:text:en_US-components/common/ActionFeedback-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/common/ActionFeedback-1728320186000","value":{"joinedGroupHub.title":"Welcome","joinedGroupHub.message":"You are now a member of this group and are subscribed to updates.","groupHubInviteNotFound.title":"Invitation Not Found","groupHubInviteNotFound.message":"Sorry, we could not find your invitation to the group. The owner may have canceled the invite.","groupHubNotFound.title":"Group Not Found","groupHubNotFound.message":"The grouphub you tried to join does not exist. It may have been deleted.","existingGroupHubMember.title":"Already Joined","existingGroupHubMember.message":"You are already a member of this group.","accountLocked.title":"Account Locked","accountLocked.message":"Your account has been locked due to multiple failed attempts. Try again in {lockoutTime} minutes.","editedGroupHub.title":"Changes Saved","editedGroupHub.message":"Your group has been updated.","leftGroupHub.title":"Goodbye","leftGroupHub.message":"You are no longer a member of this group and will not receive future updates.","deletedGroupHub.title":"Deleted","deletedGroupHub.message":"The group has been deleted.","groupHubCreated.title":"Group Created","groupHubCreated.message":"{groupHubName} is ready to use","accountClosed.title":"Account Closed","accountClosed.message":"The account has been closed and you will now be redirected to the homepage","resetTokenExpired.title":"Reset Password Link has Expired","resetTokenExpired.message":"Try resetting your password again","invalidUrl.title":"Invalid URL","invalidUrl.message":"The URL you're using is not recognized. Verify your URL and try again.","accountClosedForUser.title":"Account Closed","accountClosedForUser.message":"{userName}'s account is closed","inviteTokenInvalid.title":"Invitation Invalid","inviteTokenInvalid.message":"Your invitation to the community has been canceled or expired.","inviteTokenError.title":"Invitation Verification Failed","inviteTokenError.message":"The url you are utilizing is not recognized. Verify your URL and try again","pageNotFound.title":"Access Denied","pageNotFound.message":"You do not have access to this area of the community or it doesn't exist","eventAttending.title":"Responded as Attending","eventAttending.message":"You'll be notified when there's new activity and reminded as the event approaches","eventInterested.title":"Responded as Interested","eventInterested.message":"You'll be notified when there's new activity and reminded as the event approaches","eventNotFound.title":"Event Not Found","eventNotFound.message":"The event you tried to respond to does not exist.","redirectToRelatedPage.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.title":"Showing Related Content","redirectToRelatedPageForBaseUsers.message":"The content you are trying to access is archived","redirectToRelatedPage.message":"The content you are trying to access is archived","relatedUrl.archivalLink.flyoutMessage":"The content you are trying to access is archived View Archived Content"},"localOverride":false},"CachedAsset:component:custom.widget.Beta_MetaNav-en-1737020683553":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_MetaNav-en-1737020683553","value":{"component":{"id":"custom.widget.Beta_MetaNav","template":{"id":"Beta_MetaNav","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_MetaNav","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"MetaNav menu at the top of every page.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Beta_Footer-en-1737020683553":{"__typename":"CachedAsset","id":"component:custom.widget.Beta_Footer-en-1737020683553","value":{"component":{"id":"custom.widget.Beta_Footer","template":{"id":"Beta_Footer","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Beta_Footer","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"DevCentral´s custom footer.","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Tag_Manager_Helper-en-1737020683553":{"__typename":"CachedAsset","id":"component:custom.widget.Tag_Manager_Helper-en-1737020683553","value":{"component":{"id":"custom.widget.Tag_Manager_Helper","template":{"id":"Tag_Manager_Helper","markupLanguage":"HANDLEBARS","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Tag_Manager_Helper","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"CUSTOM","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"Helper widget to inject Tag Manager scripts into head element","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:component:custom.widget.Consent_Blackbar-en-1737020683553":{"__typename":"CachedAsset","id":"component:custom.widget.Consent_Blackbar-en-1737020683553","value":{"component":{"id":"custom.widget.Consent_Blackbar","template":{"id":"Consent_Blackbar","markupLanguage":"HTML","style":null,"texts":null,"defaults":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"components":[{"id":"custom.widget.Consent_Blackbar","form":null,"config":null,"props":[],"__typename":"Component"}],"grouping":"TEXTHTML","__typename":"ComponentTemplate"},"properties":{"config":{"applicablePages":[],"dynamicByCoreNode":false,"description":"","fetchedContent":null,"__typename":"ComponentConfiguration"},"props":[],"__typename":"ComponentProperties"},"form":null,"__typename":"Component","localOverride":false},"globalCss":null,"form":null},"localOverride":false},"CachedAsset:text:en_US-components/community/Breadcrumb-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Breadcrumb-1728320186000","value":{"navLabel":"Breadcrumbs","dropdown":"Additional parent page navigation"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagsHeaderWidget-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagsHeaderWidget-1728320186000","value":{"tag":"{tagName}","topicsCount":"{count} {count, plural, one {Topic} other {Topics}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListForNodeByRecentActivityWidget-1728320186000","value":{"title@userScope:other":"Recent Content","title@userScope:self":"Contributions","title@board:FORUM@userScope:other":"Recent Discussions","title@board:BLOG@userScope:other":"Recent Blogs","emptyDescription":"No content to show","MessageListForNodeByRecentActivityWidgetEditor.nodeScope.label":"Scope","title@instance:1706288370055":"Content Feed","title@instance:1704319314827":"Blog Feed","title@instance:1704317906837":"Content Feed","title@instance:1702668293472":"Community Feed","title@instance:1704320290851":"My Contributions","title@instance:1703720491809":"Forum Feed","title@instance:1703028709746":"Group Content Feed","title@instance:VTsglH":"Content Feed"},"localOverride":false},"Category:category:Forums":{"__typename":"Category","id":"category:Forums","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:TechnicalForum":{"__typename":"Forum","id":"board:TechnicalForum","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Forum:board:WaterCooler":{"__typename":"Forum","id":"board:WaterCooler","forumPolicies":{"__typename":"ForumPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:Articles":{"__typename":"Category","id":"category:Articles","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"displayId":"Articles"},"Tkb:board:TechnicalArticles":{"__typename":"Tkb","id":"board:TechnicalArticles","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"displayId":"TechnicalArticles","nodeType":"board","conversationStyle":"TKB","title":"Technical Articles","shortTitle":"Technical Articles","parent":{"__ref":"Category:category:Articles"}},"Tkb:board:DevCentralNews":{"__typename":"Tkb","id":"board:DevCentralNews","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:GroupsCategory":{"__typename":"Category","id":"category:GroupsCategory","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:F5-Groups":{"__typename":"Category","id":"category:F5-Groups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CommunityGroups":{"__typename":"Category","id":"category:CommunityGroups","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Occasion:board:Events":{"__typename":"Occasion","id":"board:Events","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"occasionPolicies":{"__typename":"OccasionPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Idea:board:Suggestions":{"__typename":"Idea","id":"board:Suggestions","boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"ideaPolicies":{"__typename":"IdeaPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Category:category:CrowdSRC":{"__typename":"Category","id":"category:CrowdSRC","categoryPolicies":{"__typename":"CategoryPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:codeshare":{"__typename":"Tkb","id":"board:codeshare","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:communityarticles":{"__typename":"Tkb","id":"board:communityarticles","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:security-insights":{"__typename":"Tkb","id":"board:security-insights","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Tkb:board:article-series":{"__typename":"Tkb","id":"board:article-series","tkbPolicies":{"__typename":"TkbPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}},"boardPolicies":{"__typename":"BoardPolicies","canReadNode":{"__typename":"PolicyResult","failureReason":null}}},"Conversation:conversation:287117":{"__typename":"Conversation","id":"conversation:287117","topic":{"__typename":"TkbTopicMessage","uid":287117},"lastPostingActivityTime":"2023-08-02T06:30:03.375-07:00","solved":false},"User:user:411436":{"__typename":"User","uid":411436,"login":"Sanjay_Shitole","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS00MTE0MzYtc0VDQnIw?image-coordinates=0%2C504%2C3024%2C3528"},"id":"user:411436"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTY1OTJpQjZFQjJDQ0U3M0JBNUI2MA?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTY1OTJpQjZFQjJDQ0U3M0JBNUI2MA?revision=24","title":"image.png","associationType":"BODY","width":722,"height":496,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNTUzN2k2RkNDQkFCNjE0NjVBRTkw?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNTUzN2k2RkNDQkFCNjE0NjVBRTkw?revision=24","title":"0EM1T000003K2Eq.png","associationType":"BODY","width":1225,"height":253,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTEwNThpRDU2RkZEMjdFOERCQTZDQQ?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTEwNThpRDU2RkZEMjdFOERCQTZDQQ?revision=24","title":"0EM1T000003K2Gb.png","associationType":"BODY","width":1225,"height":253,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTYzM2kxQTBDRjFGQkU2MkMxQThE?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTYzM2kxQTBDRjFGQkU2MkMxQThE?revision=24","title":"0EM1T000003K2Hh.png","associationType":"BODY","width":872,"height":540,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNDcxOGk5QzNBRDMzOUJDNjdBOUND?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNDcxOGk5QzNBRDMzOUJDNjdBOUND?revision=24","title":"0EM1T000003K2Hi.png","associationType":"BODY","width":740,"height":540,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTMwNjFpMzdFMTI5MkIxNjUyNzE4MQ?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTMwNjFpMzdFMTI5MkIxNjUyNzE4MQ?revision=24","title":"0EM1T000003K2LW.png","associationType":"BODY","width":960,"height":500,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTQxMDVpRThBNjIzQTM2NDdCQzRGNQ?revision=24\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTQxMDVpRThBNjIzQTM2NDdCQzRGNQ?revision=24","title":"0EM1T000003K2LX.png","associationType":"BODY","width":678,"height":540,"altText":null},"TkbTopicMessage:message:287117":{"__typename":"TkbTopicMessage","subject":"Using Terraform and F5® Distributed Cloud Mesh to establish secure connectivity between clouds","conversation":{"__ref":"Conversation:conversation:287117"},"id":"message:287117","revisionNum":24,"uid":287117,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:411436"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1386},"postTime":"2021-10-11T10:36:12.000-07:00","lastPublishTime":"2022-02-16T09:00:00.044-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" It is not uncommon for companies to have applications deployed independently in AWS, Azure and GCP. When these applications are required to communicate with each other, these companies must deal with operational overhead and new set of challenges such as skills gap, patching security vulnerabilities and outages, leading to bad customer experience. Setting up individual centers of excellence for managing each cloud is not the answer as it leads to siloed management and often proves costly. This is where F5 Distributed Cloud Mesh can help. Using F5® Distributed Cloud Mesh, you can establish secure connectivity with minimal changes to existing application deployments. You can do so without any outages or extended maintenance windows. \n In this blog we will go over a multi-cloud scenario in which we will establish secure connectivity between applications running in AWS and Azure. To show this, we will follow these steps \n \n Deploy simple application web servers and VPC, VNETS in AWS and Azure respectively using Terraform. \n Create virtual F5® Distributed Cloud sites for AWS and Azure using Terraform provider for Distributed Cloud platform. \n These virtual sites provide abstraction for AWS VPCs and AZURE VNETs which can then be managed and used in aggregate. \n Use terraform provider to configure F5® Distributed Cloud Mesh ingress and egress gateways to provide connectivity to the Distributed Cloud backbone. \n Configure services such as security policies, DNS, HTTP Load balancer and F5® Distributed Cloud WAAP which are required to establish secure connectivity between applications. \n \n \n Terraform provider for F5® Distributed Cloud \n F5® Distributed Cloud terraform provider can be used to configure Distributed Cloud Mesh Objects and these objects represent desired state of the system. The desired state of the system could be configuring a http/tcp load balancer, vk8s cluster, service mesh, enabling api security etc. Terraform F5® Distributed Cloud provider has more than 100 resources and data resources. Some of the resources which will be using in this example are for Distributed Cloud Services like Cloud HTTP load balancer, F5® Distributed Cloud WAAP and F5® Distributed Cloud Sites creation in AWS and Azure. You can find a list of resources here. Here are the steps to deploy simple application using F5® Distributed Cloud terraform provider on AWS & Azure. I am using below repository to create the configuration. You can also refer to the README on F5's DevCentral Git. \n \n git clone https://github.com/f5devcentral/f5-digital-customer-engagement-center.git \ncd f5-digital-customer-engagement-center/\ngit checkout mcn # checkout to multi cloud branch\n\ncd solutions/volterra/multi-cloud-connectivity/ # change dir for multi cloud scripts\n\ncustomize admin.auto.tfvars.example as per your needs\ncp admin.auto.tfvars.example admin.auto.tfvars\n\n./setup.sh # Run setup.sh file to deploy the Volterra sites which identifies services in AWS, Azure etc.\n./aws-setup.sh # Run aws-setup.sh file to deploy the application and infrastructure in AWS\n./azure-setup.sh # Run azure-setup.sh file to deploy the application and infrastructure in Azure \n \n This will create the following objects on AWS and Azure \n \n 3 VPC and VNET networks on each cloud respectively \n 3 F5® Distributed Cloud Mesh nodes on each cloud seen as master-0 \n 3 backend application on each cloud seen as scsmcn-workstation here projectPrefix is scsmcn in admin.auto.tfvars file \n 1 jump box on each cloud to test \n Create 6 http load balancers one for each node and can be accessed through F5® Distributed Cloud Console \n Create 6 F5® Distributed Cloud sites which can be accessed via F5® Distributed Cloud Console \n \n F5® Distributed Cloud Mesh does all the stitching of the VPCs and VNETs for you, you don’t need to create any transit gateway, also it stitches VPCs & VNETs to the F5® Distributed Cloud Application Delivery Network. Client when accessing backend application will use the nearest F5® Distributed Cloud Regional network http load balancer to minimize the latency using Anycast. \n Run setup.sh script to deploy the F5® Distributed Cloud sites this will create a virtual sites that will identify services deployed in AWS and Azure. \n \n ./setup.sh \n\nInitializing the backend...\n\nInitializing provider plugins...\n- Reusing previous version of hashicorp/random from the dependency lock file\n- Reusing previous version of volterraedge/volterra from the dependency lock file\n- Using previously-installed hashicorp/random v3.1.0\n- Using previously-installed volterraedge/volterra v0.10.0\n\nTerraform has been successfully initialized!\n\nrandom_id.buildSuffix: Creating...\nrandom_id.buildSuffix: Creation complete after 0s [id=c9o]\nvolterra_virtual_site.site: Creating...\nvolterra_virtual_site.site: Creation complete after 2s [id=3bde7bd5-3e0a-4fd5-b280-7434ee234117]\n\nApply complete! Resources: 2 added, 0 changed, 0 destroyed.\n\n\nOutputs:\n\nbuildSuffix = \"73da\"\nvolterraVirtualSite = \"scsmcn-site-73da\"\ncreated random build suffix and virtual site \n \n aws-setup.sh file to deploy the vpc, webservers and jump host, http load balancer, F5® Distributed Cloud aws site and origin servers \n \n ./aws-setup.sh \nInitializing modules...\n\nInitializing the backend...\n\nInitializing provider plugins...\n- Reusing previous version of volterraedge/volterra from the dependency lock file\n- Reusing previous version of hashicorp/aws from the dependency lock file\n- Reusing previous version of hashicorp/random from the dependency lock file\n- Reusing previous version of hashicorp/null from the dependency lock file\n- Reusing previous version of hashicorp/template from the dependency lock file\n- Using previously-installed hashicorp/null v3.1.0\n- Using previously-installed hashicorp/template v2.2.0\n- Using previously-installed volterraedge/volterra v0.10.0\n- Using previously-installed hashicorp/aws v3.60.0\n- Using previously-installed hashicorp/random v3.1.0\n\nTerraform has been successfully initialized!\n\nAn execution plan has been generated and is shown below.\nResource actions are indicated with the following symbols:\n + create\n <= read (data resources)\nTerraform will perform the following actions:\n\n\n # data.aws_instances.volterra[\"bu1\"] will be read during apply\n # (config refers to values not yet known)\n <= data \"aws_instances\" \"volterra\" {\n + id = (known after apply)\n + ids = (known after apply)\n\n..... truncated output ....\n\nvolterra_app_firewall.waf: Creating...\nmodule.vpc[\"bu2\"].aws_vpc.this[0]: Creating...\naws_key_pair.deployer: Creating...\nmodule.vpc[\"bu3\"].aws_vpc.this[0]: Creating...\nmodule.vpc[\"bu1\"].aws_vpc.this[0]: Creating... \naws_route53_resolver_rule_association.bu[\"bu3\"]: Creation complete after 1m18s [id=rslvr-rrassoc-d4051e3a5df442f29]\nApply complete! Resources: 90 added, 0 changed, 0 destroyed.\nOutputs:\nbu1JumphostPublicIp = \"54.213.205.230\"\nvpcId = \"{\\\"bu1\\\":\\\"vpc-051565f673ef5ec0d\\\",\\\"bu2\\\":\\\"vpc-0c4ad2be8f91990cf\\\",\\\"bu3\\\":\\\"vpc-0552e9a05bea8013e\\\"}\" \n \n azure-setup.sh will execute terraform scripts to deploy webservers, vnet, http load balancer , origin servers and F5® Distributed Cloud azure site. \n \n ./azure-setup.sh \nInitializing modules...\n\nInitializing the backend...\n\nInitializing provider plugins...\n- Reusing previous version of volterraedge/volterra from the dependency lock file\n- Reusing previous version of hashicorp/random from the dependency lock file\n- Reusing previous version of hashicorp/azurerm from the dependency lock file\n- Using previously-installed volterraedge/volterra v0.10.0\n- Using previously-installed hashicorp/random v3.1.0\n- Using previously-installed hashicorp/azurerm v2.78.0\n\nTerraform has been successfully initialized!\n\n..... truncated output ....\nazurerm_private_dns_a_record.inside[\"bu11\"]: Creation complete after 2s [id=/subscriptions/187fa2f3-5d57-4e6a-9b1b-f92ba7adbf42/resourceGroups/scsmcn-rg-bu11-73da/providers/Microsoft.Network/privateDnsZones/shared.acme.com/A/inside]\n\nApply complete! Resources: 58 added, 2 changed, 12 destroyed.\n\nOutputs:\nazureJumphostPublicIps = [\n\n \"20.190.21.3\",\n\n]\n \n \n After running terraform script you can sign in into the F5® Distributed Cloud Console at https://www.volterra.io/products/voltconsole. Click on System on the left and then Site List to list the sites, you can also enter into search string to search a particular site, Below you can find list of virtual sites deployed for Azure and AWS, status of these sites can be seen using F5® Distributed Cloud Console. \n \n AWS Sites on F5® Distributed Cloud Console \n Now in order to see the connectivity of sites to the Regional Edges, click System --> Site Map --> Click on the appropriate site you want to focus and then Connectivity --> Click AWS, Below you can see the AWS virtual sites created on F5® Distributed Cloud Console, this provides visibility, throughput, reachability and health of the infrastructure provisioned on AWS. Provides system and application level metrics. \n \n Azure Sites on F5® Distributed Cloud Console \n Below you can see the Azure virtual sites created on F5® Distributed Cloud Console, this provides visibility, throughput, reachability and health of the infrastructure provisioned on Azure. Provides system and application level metrics. \n \n Analytics on F5® Distributed Cloud Console \n To check the status of the application, sign in into the F5® Distributed Cloud Console at https://www.volterra.io/products/voltconsole. Click on the application tab --> HTTP load balancer --> select appropriate load balancer --> click Request. Below you can see various matrices for applications deployed into the AWS and Azure cloud, you can see latency at different levels like client to lb, lb to server and server to application. Also it provides HTTP requests with Error codes on application access. \n \n API First F5® Distributed Cloud Console \n F5® Distributed Cloud Console helps many operational tasks like visibility into request types, JSON payload of the request indicating browser type, device type, tenant and also request came on which http load balancers and many more details. \n \n Benefits \n OpEx Reduction: Single simplified stack can be used to manage apps in different clouds. For example, the burden of configuring security policies at different locations is avoided. Also transit cost associated with public cloud can be eliminated. \n Reduce Operational Complexity: Network expert is not required as F5® Distributed Cloud Console provides simplified way to configure and manage network and resources both at customer edge location and public cloud. Your NetOps or DevOps person can easily deploy the infrastructure or applications without network expertise. Adoption of a new cloud provider is accelerated. \n App User Experience: Customers don’t have to learn different visibility tools, F5® Distributed Cloud Console provided end to end visibility of applications which results in better user experience. Origin server or LB can be moved closer to the customer which reduces latency for apps and APIs which results in better experience. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"11374","kudosSumWeight":2,"repliesCount":3,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTY1OTJpQjZFQjJDQ0U3M0JBNUI2MA?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wy","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNTUzN2k2RkNDQkFCNjE0NjVBRTkw?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wz","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTEwNThpRDU2RkZEMjdFOERCQTZDQQ?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w0","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTYzM2kxQTBDRjFGQkU2MkMxQThE?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w1","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctNDcxOGk5QzNBRDMzOUJDNjdBOUND?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w2","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTMwNjFpMzdFMTI5MkIxNjUyNzE4MQ?revision=24\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w3","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMTctMTQxMDVpRThBNjIzQTM2NDdCQzRGNQ?revision=24\"}"}}],"totalCount":7,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:300828":{"__typename":"Conversation","id":"conversation:300828","topic":{"__typename":"TkbTopicMessage","uid":300828},"lastPostingActivityTime":"2022-10-02T18:00:00.028-07:00","solved":false},"User:user:154941":{"__typename":"User","uid":154941,"login":"Fouad_Chmainy","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS0xNTQ5NDEtMTkzOTJpNzVDODM1NDJBRUE0RTk1Mg"},"id":"user:154941"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTBpQ0JGMDA3MzAwQkQ3NUNCRQ?revision=16\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTBpQ0JGMDA3MzAwQkQ3NUNCRQ?revision=16","title":"image.png","associationType":"COVER","width":438,"height":729,"altText":""},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTFpNjA4N0ZGREFEQTgwMTZDQw?revision=16\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTFpNjA4N0ZGREFEQTgwMTZDQw?revision=16","title":"Fouad_Chmainy_0-1662639446484.png","associationType":"BODY","width":540,"height":540,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTk1OTJpQ0Q0Qzg4RTFFMDgxOEFGMg?revision=16\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTk1OTJpQ0Q0Qzg4RTFFMDgxOEFGMg?revision=16","title":"drift.jpg","associationType":"BODY","width":2441,"height":1175,"altText":null},"TkbTopicMessage:message:300828":{"__typename":"TkbTopicMessage","subject":"Manage F5 BIG-IP Advanced WAF Policies with Terraform (Intro)","conversation":{"__ref":"Conversation:conversation:300828"},"id":"message:300828","revisionNum":16,"uid":300828,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:154941"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":" This arcticle series is about the management of F5 BIG-IP Advanced WAF policies using Terraform. Its is leveraging the F5 BIG-IP Advanced WAF Declarative API and covers most of the production workflows. \n This is also a great way to cover multi-cloud deployments with a unified automation stack of F5 BIG-IP Advanced WAF Policies and a consistent security protection across all Web and API apps regardless of their location. ","introduction":"","metrics":{"__typename":"MessageMetrics","views":3962},"postTime":"2022-10-02T18:00:00.028-07:00","lastPublishTime":"2022-10-02T18:00:00.028-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" \n In this article, i will present a suite of use cases using the F5 BIG-IP Advanced WAF Terraform resources introduced on the F5 BIG-IP Terraform Provider on version 1.15. \n Introduction Requirements Description What is Terraform? F5 BIG-IP Advanced WAF Declarative API F5 BIG-IP Advanced WAF Terraform resources and data sources F5 BIG-IP Advanced WAF Policy Lifecycle Managing configuration drifts Resources Article Series \n Introduction \n Requirements \n \n It requires F5 BIG-IP TMOS minimum version v16.1 because we use the F5 BIG-IP Advanced WAF declarative API. \n Terraform version +0.11 (see minimal requirements) \n \n Description \nThe current version is 1.15 and it gives the capability to :\n \n Create a F5 BIG-IP Advanced WAF Policy \n Create an API protection policy importing an OpenAPI Specification file (V2.0 and v3.0) \n Import an existing F5 BIG-IP Advanced WAF Policy \n Manage the whole lifecycle of the F5 BIG-IP Advanced WAF Policy, including:\n \n Attack signatures \n Parameters \n Sensitive \n Exceptions on parameters \n Urls \n Exceptions on URLs \n Creating a F5 BIG-IP Advanced WAF Policy with Policy Builder and manage the learning suggestions \n \n \n \n What is Terraform? \n \n \n “HashiCorp Terraform is an infrastructure as code tool that lets you define both cloud and on-prem resources in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. » \n https://www.terraform.io/intro \n \"… but wait! Terraform is not a Configuration Management tool. I should use Ansible for that!” \n True. \n Terraform is not a config management tool and I would say: “use whatever you feel comfortable and happy working with”… but keep also that in mind: \n \n Because our F5 BIG-IP Advanced WAF API is declarative, we can tell what is our desired end state and let the system decide how to get there. \n We keep a record of the state created in the past and can easily track security changes who did what and when. \n If your underlying infrastructure is Public Cloud, you may already use Terraform for any other cloud services. You may want to reduce automation tool sprawl, to keep a consistent end-to-end state and reduce the learning and adoption curves. \n \n \n F5 BIG-IP Advanced WAF Declarative API \n We provide a comprehensive declarative REST API to provision, manage the whole lifecycle management of a F5 BIG-IP Advanced WAF policy and facilitate its integration into CI/CD pipelines. \n The documentation of the API is located here. \n \n F5 BIG-IP Advanced WAF Terraform resources and data sources \n The F5 BIG-IP Terraform resources leverage our AWAF Declarative API. \n \n The bigip_waf_policy resource compose the \"core\" of the WAF Policy. It contains the core charasteristics of the WAF Policy (partition, name, used template, enforcement mode, application language...). It also contains pointers to lists of data sources. \n The bigip_waf_entity_parameter is a data source that describe a parameter, its type, location, whether it is a sentsitive paraeter or not, attack signatures exceptions at its level... \n The bigip_waf_entity_url is a data source that describe a URL entity with its type, the protocol, allowed methods, attack signatures exceptions... \n the bigip_waf_signatures is a data source describing an attack signature, its description and its behavior (staging, enabled) \n the bigip_waf_pb_suggestions is a data source that collects all the learning suggestions from the F5 BIG-IP Advanced WAF Policy Builder for a specific F5 BIG-IP Advanced WAF Policy and a desired minimal scoring (The higher is the scoring the better it is). \n \n \n F5 BIG-IP Advanced WAF Policy Lifecycle \n Basically, the terraform workflow is very closed to what you used to with the traditional (UI) F5 BIG-IP Advanced WAF Policy workflow: \n Manually Managed \n 1. if a request is blocked, you check on the events and filter on a Support ID. \n 3. If this was a False positive generated by an attack signature, you just can just take the signature Id, and the level of the exception (globally, parameter, URL) \n 4. Create the terraform data source and attach it to the Policy \n data \"bigip_waf_entity_parameter\" \"P1\" {\n name = \"Parameter2\"\n type = \"wildcard\"\n data_type = \"alpha-numeric\"\n perform_staging = false\n signature_overrides_disable = [200001494]\n sensitive_parameter = true\n}\n\nresource \"bigip_waf_policy\" \"this\" {\n name = \"myPolicy\"\n partition = \"Common\"\n template_name = \"POLICY_TEMPLATE_RAPID_DEPLOYMENT\"\n application_language = \"utf-8\"\n enforcement_mode = \"blocking\"\n server_technologies = [\"Apache Tomcat\", \"MySQL\", \"Unix/Linux\", \"MongoDB\"]\n parameters = [data.bigip_waf_entity_parameter.P1.json]\n}\n \n \n Managed with Policy Builder suggestions \n 1. You can regularly check on the learning suggestions dashboard for potential False Positive (cleaning phase). At this point, don't accept suggestions otherwise it will enforce the change and you will have to manage the drift. \n 2. Once the cleaning is done, you can request all the policy builder learning suggestions having a desired minimum scoring (can be whatever between 10% to 100%) using the bigip_waf_pb_suggestions data source. \n data \"bigip_waf_pb_suggestions\" \"AUG3rd20221715\" {\n provider\t = bigip.prod \n policy_name = \"scenario5\"\n partition = \"Common\"\n minimum_learning_score = 100\n}\nresource \"bigip_waf_policy\" \"this\" {\n provider = bigip.prod\n application_language = \"utf-8\"\n partition = \"Common\"\n name = \"scenario5\"\n template_name = \"POLICY_TEMPLATE_FUNDAMENTAL\"\n type = \"security\"\n policy_import_json = data.http.scenario5.body\n modifications = [data.bigip_waf_pb_suggestions.AUG3rd20221715.json]\n} \n \n Managing configuration drifts \n One of the first rules we had in mind when we created these terraform resources is that we should always consider someone will perform manual changes through the F5 BIG-IP WebUI. \n The main reason is because we have a great and very convenient graphical user interface and great dashboards exposing a lot of valuable information. How would you expose all of that in HCL? \n Then, we had to make choices and release a first iteration that covers 90% of the use cases. Yet, there will always be some features that are not yet exposed. \n When you try mixing automation and manual changes is usually when problems occur... \n This is called configuration drifts and we hate config drifts because it means we have to resolve something and make hard choices! \n So... in case of a drift, you either override any changes that have been made manually or you accept the changes, but how do you keep track of these changes in your state? \n \n \n \n let's take an example: you are the terraform admin and you have to go on very well deserved PTO. During your vacations, one of your colleague have to make changes into the WAF Policy: enforcing a new CVE protection, adding some potential exception because the application changed,... \n When you are back, by planning the next terraform changes you realize there is a configuration drift between your local terraform state and the remote state on the BIG-IP. In that case, you just have to import the current state from the BIG-IP (terraform import) or point to an external repo of your new policy and use it as the policy_json attribute of your bigip_waf_policy terraform resource. \n \n Resources \nTerraform Registry documentation \n F5 BIG-IP Terraform Provider \n Lab guide \n \n Article Series \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Intro) \n \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Part 1 - Policy Creation) \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Part 2 - Policy Import) \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Part 3 - Migrate) \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Part 4 - Policy Lifecycle management) \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Part 5 - Working with Policy Builder) \n Manage F5 BIG-IP Advanced WAF Policies with Terraform (Best Practices) \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"8403","kudosSumWeight":4,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTBpQ0JGMDA3MzAwQkQ3NUNCRQ?revision=16\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wy","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTkzOTFpNjA4N0ZGREFEQTgwMTZDQw?revision=16\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wz","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0zMDA4MjgtMTk1OTJpQ0Q0Qzg4RTFFMDgxOEFGMg?revision=16\"}"}}],"totalCount":3,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:287131":{"__typename":"Conversation","id":"conversation:287131","topic":{"__typename":"TkbTopicMessage","uid":287131},"lastPostingActivityTime":"2022-05-13T12:14:49.118-07:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMzEtODQyNmkyRkRFRUVCRjYyNTU2N0FB?revision=3\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMzEtODQyNmkyRkRFRUVCRjYyNTU2N0FB?revision=3","title":"0EM1T000002Is0Y.png","associationType":"BODY","width":816,"height":421,"altText":null},"TkbTopicMessage:message:287131":{"__typename":"TkbTopicMessage","subject":"Automating certificate lifecycle management with HashiCorp Vault","conversation":{"__ref":"Conversation:conversation:287131"},"id":"message:287131","revisionNum":3,"uid":287131,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:411436"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":4039},"postTime":"2020-10-09T14:17:14.000-07:00","lastPublishTime":"2022-05-13T12:14:49.118-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" One of the challenges many enterprises face today, is keeping track of various certificates and ensuring those which are associated with critical applications deployed across multi-cloud are current and valid. This integration helps you to improve your security poster with short lived dynamic SSL certificates using HashiCorp Vault and AS3 on BIG-IP. \n First, a bit about AS3… \n Application Services 3 Extension (referred to as AS3 Extension or more often simply AS3) is a flexible, low-overhead mechanism for managing application-specific configurations on a BIG-IP system. AS3 uses a declarative model, meaning you provide a JSON declaration rather than a set of imperative commands. The declaration represents the configuration which AS3 is responsible for creating on a BIG-IP system. AS3 is well-defined according to the rules of JSON Schema, and declarations validate according to JSON Schema. AS3 accepts declaration updates via REST (push), reference (pull), or CLI (flat file editing). \n What is Vault? \n Vault is a tool for securely accessing secrets. A secret is anything that you want to tightly control access to, such as API keys, passwords, or certificates. Vault provides a unified interface to any secret, while providing tight access control and recording a detailed audit log. A modern system requires access to a multitude of secrets: database credentials, API keys for external services, credentials for service-oriented architecture communication, etc. Understanding who is accessing what secrets is already very difficult and platform specific. Adding on key rolling, secure storage, and detailed audit logs is almost impossible without a custom solution. This is where Vault steps in. \n Public Key Infrastructure (PKI) provides a way to verify authenticity and guarantee secure communication between applications. Setting up your own PKI infrastructure can be a complex and very manual process. Vault PKI allows users to dynamically generate X.509 certificates quickly and on demand. Vault PKI can streamline distributing TLS certificates and allows users to create PKI certificates with a single command. Vault PKI reduces overhead around the usual manual process of generating a private key and CSR, submitting to a CA, and waiting for a verification and signing process to complete, while additionally providing an authentication and authorization mechanism to validate as well. \n Benefits of using Vault automation for BIG-IP \n \n Cloud and platform independent solution for your application anywhere (public cloud or private cloud) \n Uses vault agent and Leverages AS3 Templating to update expiring certificates \n No application downtime - Dynamically update configuration without affecting traffic \n \n Configuration: \n 1. Setting up the environment - deploy instances of BIG-IP VE and Vault in cloud or on-premises \n You can create instances in the cloud for Vault & BIG-IP using terraform. The repo https://github.com/f5devcentral/f5-certificate-rotate \n This will pretty much download Vault binary and start the Vault server. Also, it will deploy the F5 BIG-IP instance on the AWS Cloud. Once we have the instances ready, you can SSH into the Vault ubuntu server and change directory to /tmp and execute below commands. \n # Point to the Vault Server\nexport VAULT_ADDR=http://127.0.0.1:8200 \n\n# Export the Vault Token\nexport VAULT_TOKEN=root \n\n# Create roles and define allowed domains with TTL for Certificate\nvault write pki/roles/web-certs allowed_domains=demof5.com ttl=160s max_ttl=30m allow_subdomains=true\n\n# Enable the app role\nvault auth enable approle\n\n# Create a app policy and apply https://github.com/f5devcentral/f5-certificate-rotate/blob/master/templates/app-pol.hcl\nvault policy write app-pol app-pol.hcl\n\n# Apply the app policy using app role\nvault write auth/approle/role/web-certs policies=\"app-pol\"\n\n# Read the Role id from the Vault\nvault read -format=json auth/approle/role/web-certs/role-id | jq -r '.data.role_id' > roleID\n\n# Using the role id use the secret id to authenticate vault server\nvault write -f -format=json auth/approle/role/web-certs/secret-id | jq -r '.data.secret_id' > secretID\n\n# Finally run the Vault agent using the config file\nvault agent -config=agent-config.hcl -log-level=debug\n \n \n 2. Use AS3 Template file certs.tmpl with the values as shown \n The template file shown below will be automatically uploaded to the Vault instance, the ubuntu server in the /tmp directory \n Here I am using an AS3 file called certs.tmpl which is templatized as shown below. \n {{ with secret \"pki/issue/web-certs\" \"common_name=www.demof5.com\" }}\n[\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/remark\",\n \"value\": \"Updated on {{ timestamp }}\"\n },\n\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/certificate\",\n \"value\": \"{{ .Data.certificate | toJSON | replaceAll \"\\\"\" \"\" }}\"\n },\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/privateKey\",\n \"value\": \"{{ .Data.private_key | toJSON | replaceAll \"\\\"\" \"\" }}\"\n\n },\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/chainCA\",\n \"value\": \"{{ .Data.issuing_ca | toJSON | replaceAll \"\\\"\" \"\" }}\"\n }\n]\n{{ end }}\n \n \n 3. Vault will render a new JSON payload file called certs.json whenever the SSL Certs expires \n When the Certificate expires, Vault generates a new Certificate which we can use to update the BIG-IP using ssh script, below shows the certs.json created automatically. \n Snippet of certs.json being created \n [\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/remark\",\n \"value\": \"Updated on 2020-10-02T19:05:53Z\"\n },\n {\n \"op\": \"replace\",\n \"path\": \"/Demof5/HTTPS/webcert/certificate\",\n \"value\": \"-----BEGIN CERTIFICATE-----\\nMIIDSDCCAjCgAwIBAgIUaMgYXdERwzwU+tnFsSFld3DYrkEwDQYJKoZIhvcNAQEL\\nBQAwEzERMA8GA1UEAxMIZGVtby5jb20wHhcNMjAxMDAyMTkwNTIzWhcNMj\n \n \n 4. Use Vault Agent file to run the integration forever without application traffic getting affected \n Example Vault Agent file \n pid_file = \"./pidfile\"\n\nvault {\n address = \"http://127.0.0.1:8200\"\n}\n\nauto_auth {\n\n method \"approle\" {\n mount_path = \"auth/approle\"\n config = {\n role_id_file_path = \"roleID\"\n secret_id_file_path = \"secretID\"\n remove_secret_id_file_after_reading = false\n }\n }\n\n sink \"file\" {\n config = {\n path = \"approleToken\"\n }\n }\n}\n\ntemplate {\n source = \"./certs.tmpl\"\n destination = \"./certs.json\"\n #command = \"bash updt.sh\"\n}\ntemplate {\n source = \"./https.tmpl\"\n destination = \"./https.json\"\n}\n \n 5. For Integration with HCP Vault \n If you are using HashiCorp hosted Vault solution instead of standalone Vault you can still use this solution with making few changes in the vault agent file. Detail documentation when using HCP vault is here at README. You can map tenant application objects on BIG-IP to Namespace on HCP Vault which provides islotation. More details how to create this solution at https://github.com/f5businessdevelopment/f5-hcp-vault \n Summary \n The integration has following components listed below, here the Venafi or Lets Encrypt can also be used as external CA. \n \n Using this solution, you are able to: \n \n Improve your security posture with short lived dynamic certificates \n Automatically update applications using templating and robust AS3 service \n Increased collaborating breaking down silos \n Cloud agnostic solution can be deployed on-prem or public cloud \n ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"9022","kudosSumWeight":4,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMzEtODQyNmkyRkRFRUVCRjYyNTU2N0FB?revision=3\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:281697":{"__typename":"Conversation","id":"conversation:281697","topic":{"__typename":"TkbTopicMessage","uid":281697},"lastPostingActivityTime":"2022-03-23T09:35:26.704-07:00","solved":false},"User:user:150953":{"__typename":"User","uid":150953,"login":"Eric_Chen","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS0xNTA5NTMtZXB1akpu?image-coordinates=267%2C0%2C1348%2C1080"},"id":"user:150953"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMTE1NTRpNTA4MjkzNDYxN0ZEODQzNg?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMTE1NTRpNTA4MjkzNDYxN0ZEODQzNg?revision=1","title":"0151T000003q47AQAQ.png","associationType":"BODY","width":601,"height":338,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMzg4MmkwRkU3OTNDQjZBMjcyMjU0?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMzg4MmkwRkU3OTNDQjZBMjcyMjU0?revision=1","title":"0151T000003q2o2QAA.png","associationType":"BODY","width":600,"height":538,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNTY1NmlEOEQxNDlBRkE2OUYzMDIy?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNTY1NmlEOEQxNDlBRkE2OUYzMDIy?revision=1","title":"0151T000003q2oRQAQ.png","associationType":"BODY","width":300,"height":174,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNjY4NWlBQzgyNDYzNTg3MEZDN0ZE?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNjY4NWlBQzgyNDYzNTg3MEZDN0ZE?revision=1","title":"0151T000003q2oMQAQ.png","associationType":"BODY","width":300,"height":493,"altText":null},"TkbTopicMessage:message:281697":{"__typename":"TkbTopicMessage","subject":"Pushing Updates to BIG-IP w/ HashiCorp Consul Terraform Sync","conversation":{"__ref":"Conversation:conversation:281697"},"id":"message:281697","revisionNum":1,"uid":281697,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:150953"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1611},"postTime":"2020-12-14T08:25:58.000-08:00","lastPublishTime":"2020-12-14T08:25:58.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" HashiCorp Consul Terraform Sync (CTS) is a tool/daemon that allows you to push updates to your BIG-IP devices in near real-time (this is also referred to as Network Infrastructure Automation). This helps in scenarios where you want to preserve an existing set of network/security policies and deliver updates to application services faster. Consul Terraform Sync Consul is a service registry that keeps track of where a service is (10.1.20.10:80 and 10.1.20.11:80) and the health of the service (responding to HTTP requests). Terraform allows you to push updates to your infrastructure, but usually in a one and done fashion (fire and forget). NIA is a symbiotic relationship of Terraform and Consul. It allows you to track changes via Consul (new node added/removed from a service) and push the change to your infrastructure via Terraform. Putting CTS in Action We can use CTS to help solve a common problem of how to enable a network/security team to allow an application team to dynamically update the pool members for their application. This will be accomplished by defining a virtual server on the BIG-IP and then enabling the application team to update the state of the pool members (but not allow them to modify the virtual server itself). Defining the Virtual Server The first step is that we want to define what services we want. In this example we use a FAST template to generate an AS3 declaration that will generate a set of Event-Driven Service Discovery pools. The Event-Driven pools will be updated by NIA and we will apply an iControl REST RBAC policy to restrict updates. The FAST template takes the inputs of “tenant”, “virtual server IP”, and “services”. This generates a Virtual Server with 3 pools. Event-Driven Service Discovery Each of the pools is created using Event-Driven Service Discovery that creates a new API endpoint with a path of: /mgmt/shared/service-discovery/task/ ~[tenant]~EventDrivenApps~[service]_pool/nodes\n You can send a POST API call these to add/remove pool members (it handles creation/deletion of nodes). The format of the API call is an array of node objects: [{“id”:”[identifier]”,”ip”:”[ip address]”,”port”:[port (optional)]}]\n We can use iControl REST RBAC to limit access to a user to only allow updates via the Event-Driven API. Creating a CTS Task NIA can make use of existing Terraform providers including the F5 BIG-IP Provider. We create our own module that makes use of the Event-Driven API ...\nresource \"bigip_event_service_discovery\" \"pools\" {\n for_each = local.service_ids\n taskid = \"~EventDriven~EventDrivenApps~${each.key}_pool\"\n dynamic \"node\" {\n for_each = local.groups[each.key]\n content {\n id = node.value.node\n ip = node.value.node_address\n port = node.value.port\n }\n }\n}\n...\n Once NIA is run we can see it updating the BIG-IP - Finding f5networks/bigip versions matching \"~> 1.5.0\"...\n...\nmodule.AS3.bigip_event_service_discovery.pools[\"app003\"]: Creating...\n…\nmodule.AS3.bigip_event_service_discovery.pools[\"app002\"]: Creation complete after 0s [id=~EventDriven~EventDrivenApps~app002_pool]\n\nApply complete! Resources: 3 added, 0 changed, 0 destroyed.\n Scaling up the environment to go from 3 pool members to 10 you can see NIA pick-up the changes and apply them to the BIG-IP in near real-time. module.AS3.bigip_event_service_discovery.pools[\"app001\"]: Refreshing state... [id=~EventDriven~EventDrivenApps~app001_pool]\n…\nmodule.AS3.bigip_event_service_discovery.pools[\"app002\"]: Modifying... [id=~EventDriven~EventDrivenApps~app002_pool]\n…\nmodule.AS3.bigip_event_service_discovery.pools[\"app002\"]: Modifications complete after 0s [id=~EventDriven~EventDrivenApps~app002_pool]\n\nApply complete! Resources: 0 added, 3 changed, 0 destroyed.\n\n NIA can be run interactively at the command-line, but you can also run it as a system service (i.e. under systemd). Alternate Method In the previous example you saw an example of using AS3 to define the Virtual Server resource. You can also opt to use Event-Driven API directly on an existing BIG-IP pool (just be warned that it will obliterate any existing pool members once you send an update via the Event-Driven nodes API). To create a new Event-Driven pool you would send a POST call with the following payload to /mgmt/shared/service-discovery/task {\n \"id\": \"test_pool\",\n \"schemaVersion\": \"1.0.0\",\n \"provider\": \"event\",\n \"resources\": [\n {\n \"type\": \"pool\",\n \"path\": \"/Common/test_pool\",\n \"options\": {\n \"servicePort\": 8080\n }\n }\n ],\n \"nodePrefix\": \"/Common/\"\n}\n You would then be able to access it with the id of “test_pool”. To remove it from Event-Driven Service Discovery you would send a DELETE call to /mgmt/shared/service-discovery/task/test_pool Separation of Concerns In this example you saw how CTS could be used to separate network, security, and application tasks, but these could be easily combined using NIA just as easily. Consul Terraform Sync is now generally available, and I look forward to seeing how you can leverage it. For an example that is similar to this article you can take a look at the following GitHub repo that has an example of using NIA. You can also view another example on the Terraform registry as well. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"5761","kudosSumWeight":1,"repliesCount":8,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMTE1NTRpNTA4MjkzNDYxN0ZEODQzNg?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wy","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctMzg4MmkwRkU3OTNDQjZBMjcyMjU0?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wz","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNTY1NmlEOEQxNDlBRkE2OUYzMDIy?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w0","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODE2OTctNjY4NWlBQzgyNDYzNTg3MEZDN0ZE?revision=1\"}"}}],"totalCount":4,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:287122":{"__typename":"Conversation","id":"conversation:287122","topic":{"__typename":"TkbTopicMessage","uid":287122},"lastPostingActivityTime":"2021-04-15T08:59:44.000-07:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjItMTU0MmkxRTRDNDAxNUIzMzJDMUQ1?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjItMTU0MmkxRTRDNDAxNUIzMzJDMUQ1?revision=1","title":"0EM1T000002bzvJ.png","associationType":"BODY","width":926,"height":396,"altText":null},"TkbTopicMessage:message:287122":{"__typename":"TkbTopicMessage","subject":"Consistent Security and performance across clouds using BIG-IP and Terraform","conversation":{"__ref":"Conversation:conversation:287122"},"id":"message:287122","revisionNum":1,"uid":287122,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:411436"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":535},"postTime":"2021-04-15T08:59:44.000-07:00","lastPublishTime":"2021-04-15T08:59:44.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" As reported by IDC, enterprises are increasingly considering deploying applications and services into multiple public clouds. This presents a new set of challenges: configuring virtual compute, storage, network, and middleware services on each of these clouds require cloud specific skills and configuration normalization to ensure same customer experience. In my previous blog, I went through how to configure BIG-IP as a part of your CICD pipeline using Terraform and GitHub Actions. As you might know BIG-IP Virtual Editions can be deployed in all major public cloud using Terraform. In this article, I will cover how to consistently apply configurations across BIG-IP Virtual Editions running in multi-cloud using Terraform Automation. We will use templating for AS3 and will build declarations that you can apply to BIG-IP running in any cloud using Terraform. \n\n Environment \n\n For this use case example, I will deploy a WAF policy on the BIG-IP devices running in AWS and Azure. BIG-IP VE instances and backend applications instances are created using the terraform scripts found here, but the following instructions will work on any cloud deployed BIG-IP VEs & applications. \n\n I will use an AS3 declaration which will configure a new tenant on the BIG-IP with a virtual server, a pool, and nodes. I will apply the same declaration with an associated WAF policy to virtual BIG-IP instances in AWS and Azure clouds using Terraform. \n\n \n\n Prerequisites \n\n 1. An AWS Account \n\n 2. An Azure Account \n\n 3. BIG-IP VE v14+ instance running on AWS and Azure \n\n 4. The ASM module is licensed and activated on your BIG-IP \n\n 5. Terraform installed on your local or remote jump box \n\n \n\n Let’s get started… \n\n \n\n AS3 Declaration \n\n Below is an example of an AS3 declaration for creating a virtual server and attaching a WAF security policy to it. At a minimum, you will need to edit the IPs to match your environment. \n\n {\n \"class\": \"AS3\",\n \"action\": \"deploy\",\n \"persist\": true,\n \"declaration\": {\n \"class\": \"ADC\",\n \"schemaVersion\": \"3.24.0\",\n \"id\": \"Protected_App\",\n \"My_Protected_App\": {\n \"class\": \"Tenant\",\n \"App\": {\n \"class\": \"Application\",\n \"template\": \"http\",\n \"serviceMain\": {\n \"class\": \"Service_HTTP\",\n \"virtualPort\": 8080,\n \"virtualAddresses\": [\n \"10.2.1.200\"\n ],\n \"pool\": \"web_pool\",\n \"policyWAF\": {\n \"use\": \"My_ASM_Policy\"\n },\n \"persistenceMethods\": [],\n \"profileMultiplex\": {\n \"bigip\": \"/Common/oneconnect\"\n }\n },\n \"web_pool\": {\n \"class\": \"Pool\",\n \"monitors\": [\n \"http\"\n ],\n \"members\": [\n {\n \"servicePort\": 80,\n \"serverAddresses\": [\n \"10.2.1.101\",\n \"10.2.1.102\"\n ]\n }\n ]\n },\n \"My_ASM_Policy\": {\n \"class\": \"WAF_Policy\",\n \"url\": \"https://raw.githubusercontent.com/scshitole/more-terraform/master/Sample_app_sec_02_waf_policy.xml\",\n \"ignoreChanges\": true\n }\n }\n }\n }\n }\n \n\n \n\n Using Terraform to configure the BIG-IP \n\n I am using terraform to deploy the AS3 declaration above, which configures the Virtual Server and attaches the ASM WAF policy. The WAF Policy URL is also declared in the AS3 as shown above. \n\n The BIG-IP can be provisioned in Azure using the ‘terraform-Azure-bigip-module’ located at https://github.com/f5devcentral/terraform-azure-bigip-module. Once done, I use Terraform configuration below to deploy the secure application configuration using the bigip-as3 resource which is part of BIG-IP Terraform provider. Terraform configuration is located at https://github.com/scshitole/mcloud/blob/main/terraform-azure-bigip-module/examples/as3/main.tf \n\n Example Terraform TF for Azure Cloud \n\n provider \"azurerm\" {\n features {}\n}\n\n\nterraform {\n required_providers {\n bigip = {\n source = \"f5networks/bigip\"\n version = \"1.8.0\"\n }\n }\n}\n\n\nprovider \"bigip\" {\n address = var.address\n username = \"admin\"\n password = var.password\n port = var.port\n}\n\n\nresource \"bigip_as3\" \"as3-waf\" {\n as3_json = file(var.declaration)\n}\n\n\nresource \"azurerm_network_interface\" \"appnic\" {\n count = var.app_count\n name = \"app_nic\"\n location = var.location\n resource_group_name = var.resource_group\n\n\n ip_configuration {\n name = \"testConfiguration\"\n subnet_id = var.subnet_id\n private_ip_address_allocation = \"Static\"\n private_ip_address = \"10.2.1.101\"\n }\n}\n\nresource \"azurerm_managed_disk\" \"appdisk\" {\n name = \"datadisk_existing_${count.index}\"\n count = var.app_count\n location = var.location\n resource_group_name = var.resource_group\n storage_account_type = \"Standard_LRS\"\n create_option = \"Empty\"\n disk_size_gb = \"1023\"\n}\n\nresource \"azurerm_availability_set\" \"avset\" {\n name = \"avset\"\n location = var.location\n resource_group_name = var.resource_group\n platform_fault_domain_count = 2\n platform_update_domain_count = 2\n managed = true\n}\n\nresource \"azurerm_virtual_machine\" \"app\" {\n count = var.app_count\n name = \"app_vm_${count.index}\"\n location = var.location\n availability_set_id = azurerm_availability_set.avset.id\n resource_group_name = var.resource_group\n network_interface_ids = [element(azurerm_network_interface.appnic.*.id, count.index)]\n vm_size = \"Standard_DS1_v2\"\n\n # Uncomment this line to delete the OS disk automatically when deleting the VM\n delete_os_disk_on_termination = true\n\n # Uncomment this line to delete the data disks automatically when deleting the VM\n delete_data_disks_on_termination = true\n\n storage_image_reference {\n publisher = \"Canonical\"\n offer = \"UbuntuServer\"\n sku = \"16.04-LTS\"\n version = \"latest\"\n }\n\n storage_os_disk {\n name = \"myosdisk${count.index}\"\n caching = \"ReadWrite\"\n create_option = \"FromImage\"\n managed_disk_type = \"Standard_LRS\"\n }\n\n\n # Optional data disks\n storage_data_disk {\n name = \"datadisk_new_${count.index}\"\n managed_disk_type = \"Standard_LRS\"\n create_option = \"Empty\"\n lun = 0\n disk_size_gb = \"1023\"\n }\n\n storage_data_disk {\n name = element(azurerm_managed_disk.appdisk.*.name, count.index)\n managed_disk_id = element(azurerm_managed_disk.appdisk.*.id, count.index)\n create_option = \"Attach\"\n lun = 1\n disk_size_gb = element(azurerm_managed_disk.appdisk.*.disk_size_gb, count.index)\n }\n\n os_profile {\n computer_name = format(\"appserver-%s\", count.index)\n admin_username = \"appuser\"\n admin_password = var.upassword\n }\n\n os_profile_linux_config {\n disable_password_authentication = false\n }\n\n tags = {\n Name = \"${var.prefix}-app\"\n }\n}\n \n\n Example Terraform TF for AWS Cloud \n\n The BIG-IP can be deployed using the terraform module for AWS located at https://github.com/f5devcentral/terraform-aws-bigip, once done I am using the below TF configuration to deploy the application and the AS3 application objects using terraform BIG-IP provider resource bigip-as3 in AWS Cloud, this will also protect the application using the ASM WAF policy defined in the AS3. Terraform TF file configuration is located at https://github.com/scshitole/mcloud/blob/main/terraform-aws-bigip/examples/as3/main.tf \n\n terraform {\n\t required_providers {\n\t bigip = {\n\t source = \"f5networks/bigip\"\n\t version = \"1.8.0\"\n\t }\n\t }\n\t}\n\t\n\tprovider \"bigip\" {\n\t address = var.address\n\t username = \"admin\"\n\t password = var.password\n\t port= var.port\n\t}\n\t\n\tresource \"bigip_as3\" \"as3-waf\" {\n\t as3_json = file(var.declaration)\n\t}\n\t\n\n\tprovider \"aws\" {\n\t profile = \"default\"\n\t region = \"us-east-2\"\n\t}\n\t\n\tdata \"aws_ami\" \"ubuntu\" {\n\t most_recent = true\n\t\n\t filter {\n\t name = \"name\"\n\t values = [\"ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*\"]\n\t }\n\t\n\t filter {\n\t name = \"virtualization-type\"\n\t values = [\"hvm\"]\n\t }\n\t\n\t owners = [\"099720109477\"] # Canonical\n\t}\n\t\n\tresource \"aws_instance\" \"example\" {\n\t ami = data.aws_ami.ubuntu.id\n\t instance_type = \"t2.micro\"\n\t private_ip = \"10.0.0.100\"\n\t subnet_id = var.subnet_id\n\t tags = {\n\t Name = \"scs-minstance\"\n\t }\n\t}\n \n\n Conclusion \n\n With Terraform automation, BIG-IP and AS3 can facilitate consistent network, security and performance configurations for applications across multiple clouds, both public and private. As shown above, you can create and use the same AS3 declaration (same load balancing and WAF policy) for applications running in AWS and Azure. The AS3 template I showed can be customized for HTTP Services, TLS Encryption, Network Security, Application Security, DOS Protection etc. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"11187","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjItMTU0MmkxRTRDNDAxNUIzMzJDMUQ1?revision=1\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:287128":{"__typename":"Conversation","id":"conversation:287128","topic":{"__typename":"TkbTopicMessage","uid":287128},"lastPostingActivityTime":"2021-03-09T09:31:38.000-08:00","solved":false},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTUxNjRpM0UxRTMzMDczRjE5M0Y3Mw?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTUxNjRpM0UxRTMzMDczRjE5M0Y3Mw?revision=1","title":"0EM1T000002bBxd.png","associationType":"BODY","width":658,"height":197,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTI4MzVpRDFGRDdGOEI1NzIyRDExOQ?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTI4MzVpRDFGRDdGOEI1NzIyRDExOQ?revision=1","title":"0EM1T000002bBxn.png","associationType":"BODY","width":418,"height":178,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM3OWk5RjU0QjE2M0NFODExQ0Yx?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM3OWk5RjU0QjE2M0NFODExQ0Yx?revision=1","title":"0EM1T000002b8k2.png","associationType":"BODY","width":2500,"height":692,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjE2N2kwM0M4MjJFRDJGQzgyQzRC?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjE2N2kwM0M4MjJFRDJGQzgyQzRC?revision=1","title":"0EM1T000002b8ln.png","associationType":"BODY","width":2222,"height":1088,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTQ5ODFpRTcxOTMwNTZDMTI3NkMwNg?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTQ5ODFpRTcxOTMwNTZDMTI3NkMwNg?revision=1","title":"0EM1T000002b8mW.png","associationType":"BODY","width":2018,"height":514,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTE5MTJpMjBBRTAwODNCRkYzMzhBMA?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTE5MTJpMjBBRTAwODNCRkYzMzhBMA?revision=1","title":"0EM1T000002b8mX.png","associationType":"BODY","width":1896,"height":1498,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtODg5MWlBN0Q5MEVENkM3OTNFQjFF?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtODg5MWlBN0Q5MEVENkM3OTNFQjFF?revision=1","title":"0EM1T000002b8mY.png","associationType":"BODY","width":1938,"height":544,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjI5MWkxQzUxNTMxNDdGRjI1QUYx?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjI5MWkxQzUxNTMxNDdGRjI1QUYx?revision=1","title":"0EM1T000002b8mZ.png","associationType":"BODY","width":2796,"height":912,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM4OWk2QzgyOUNGMTk2OTgwRUZE?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM4OWk2QzgyOUNGMTk2OTgwRUZE?revision=1","title":"0EM1T000002b8ma.png","associationType":"BODY","width":2834,"height":1276,"altText":null},"TkbTopicMessage:message:287128":{"__typename":"TkbTopicMessage","subject":"Integrate BIG-IP policy management into CI/CD pipeline using Terraform and GitHub Actions","conversation":{"__ref":"Conversation:conversation:287128"},"id":"message:287128","revisionNum":1,"uid":287128,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:411436"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1311},"postTime":"2021-03-09T09:31:38.000-08:00","lastPublishTime":"2021-03-09T09:31:38.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" AS3 (Application Services 3) is a part of F5 Automation Toolchain which provides a flexible, low overhead mechanism for managing configurations on a BIG-IP device. In this blog, I will show you how to integrate your security and network policy management into your CICD pipelines using AS3, Terraform, GitHub Actions. \n\n With Terraform and GitHub Actions, you can enable continuous integration and deployment practices to automate, test and deploy BIG-IP configurations as part of a pipeline. \n\n Environment Setup \n\n In the rest of this blog, we will go over how to create a sample workflow using GitHub Actions and Terraform. This workflow will be used to deploy an AS3 template which contains WAF (ASM) policy that will protect the backend application from any attacks. \n\n \n\n Prerequisite \n\n · BIG-IP device with AS3 rpm installed and ASM enabled. \n\n · Backend application instance \n\n · GitHub account \n\n · AWS account \n\n · Local instance of Terraform installed and running (I am using Terraform version 0.14.7) \n\n · Terraform Cloud account \n\n \n\n Setting up local CLI for Terraform Cloud \n\n Sign in into Terraform cloud at https://www.terraform.io/ \n\n Click on Create a New workspace, select CLI (Command Line Interface) Driven Workspace and assign your workspace a name – e.g., ‘bigip-ci’ \n\n Leave the browser window and go to your terminal to clone the ‘f5devcentral/bigip-ci.git’ repository. \n\n \n\n \ngit clone https://github.com/f5devcentral/bigip-ci.git\ncd bigip-ci\nterraform login\n \n\n \n\n When prompted, say ‘YES’ to proceed. This will open a new browser window where you will be asked to Create API token as shown. Give a name for your token and click ‘create API token’. \n\n \n\n Copy the token you created and paste it into your terminal window. Your terminal will be waiting for input as shown. \n\n \nToken for app.terraform.io:\nEnter a value: <your token>\n\n \n\n Set up GitHub environment to access AWS and Terraform Cloud \n\n Go to https://github.com/<yourusername>/bigip-ci/settings/secrets/actions and create the secrets as shown below, also update the TF_API_TOKEN which you have created before \n\n \n\n \n\n Enter all the secrets as shown above in your GitHub repo - AWS Secrets Key and Key ID, also update ASW_SESSION_TOKEN if you are using it. \n\n Add your infrastructure details in Terraform cloud \n\n On the Terraform Cloud, under the Workspace bigip-ci update the terraform variables listed below. \n\n BIG-IP variables - address, port, username, password. Variable deployWAF is the AS3 configuration file that has a WAF policy referenced. You can customize this to meet your requirements. \n\n \n\n \n\n Before proceeding, review the main.tf and deployWAF.json and customize it as per your deployment. \n\n \ncat main.tf \nterraform {\n required_providers {\n bigip = {\n source = \"F5Networks/bigip\"\n version = \"1.4.0\"\n }\n }\n backend \"remote\" {\n organization = \"SCStest\"\n workspaces {\n name = \"bigip-ci\"\n }\n }\n}\nprovider \"aws\" {\n region = \"us-west-2\"\n}\nprovider \"bigip\" {\n address = \"https://${var.address}:${var.port}\"\n username = var.username\n password = var.password\n}\n\n# deploy application using as3\nresource \"bigip_as3\" \"DeployApp\" {\n as3_json = file(var.deployWAF)\n}\n \n\n \n\n Testing the CI workflow \n\n Our environment is now setup such that the Actions workflow gets trigged when there is a PULL REQUEST to the MASTER branch. Let’s test it out by committing a minor change. On the terminal execute: \n\n \n# check you are pointing to which branch\ngit status\n# checkout to the dev branch\ngit checkout dev. \n# add the changed files to gitHub, this will be your main.tf and deployWAF.json \ngit add .\ngit commit -m \"deployWAF\"\n# push the files to dev branch\ngit push\n \n\n \n\n Create a pull request, merge to master to trigger the Actions Workflow \n\n \n\n \n\n \n\n \n\n Merge the pull request: \n\n \n\n \n\n Click on the ‘Actions’ tab in your GitHub repo to see the trigged workflow as shown below: \n\n \n\n \n\n \n\n When you click on the workflow, you can see the summary of jobs that are executed. A green check means the run was successful. \n\n \n\n \n\n The GitHub Actions Workflow \n\n The above merge of the Pull Request executed the sample workflow at .github/workflow/bigip-ci.yml. As shown below, the workflow has various ‘event definitions’ and ‘jobs’. In this case the event is on pull_request, and the jobs are terraform runs. The jobs listed in this workflow are: Setup Terraform, Terraform Init, Terraform Plan and Terraform Apply. \n\n \nname: \"bigip_waf\"\n\non:\n push:\n branches:\n - master\n pull_request:\n\njobs:\n terraform:\n name: \"Terraform\"\n runs-on: ubuntu-latest\n steps:\n - name: Checkout\n uses: actions/checkout@v2\n\n - name: Setup Terraform\n uses: hashicorp/setup-terraform@v1\n with:\n # terraform_version: 0.13.0:\n cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}\n\n - name: Terraform Init\n id: init\n run: terraform init\n\n - name: Terraform Plan\n id: plan\n if: github.event_name == 'pull_request'\n run: terraform plan -no-color\n continue-on-error: true\n\n - uses: actions/github-script@0.9.0\n if: github.event_name == 'pull_request'\n env:\n PLAN: \"terraform\\n${{ steps.plan.outputs.stdout }}\"\n with:\n github-token: ${{ secrets.GITHUB_TOKEN }}\n script: |\n const output = `#### Terraform Format and Style 🖌\\`${{ steps.fmt.outcome }}\\`\n #### Terraform Initialization ⚙️\\`${{ steps.init.outcome }}\\`\n #### Terraform Plan 📖\\`${{ steps.plan.outcome }}\\`\n\n <details><summary>Show Plan</summary>\n\n \\`\\`\\`${process.env.PLAN}\\`\\`\\`\n\n </details>\n\n *Pusher: @${{ github.actor }}, Action: \\`${{ github.event_name }}\\`*`;\n\n \n github.issues.createComment({\n issue_number: context.issue.number,\n owner: context.repo.owner,\n repo: context.repo.repo,\n body: output\n })\n\n - name: Terraform Plan Status\n if: steps.plan.outcome == 'failure'\n run: exit 1\n\n - name: Terraform Apply\n if: github.ref == 'refs/heads/master' && github.event_name == 'push'\n run: terraform apply -auto-approve\n \n\n \n\n Conclusion: \n\n BIG-IP policy management can be very easily included into your CI/CD pipelines. You can use any tools such as Jenkins, GitHub actions etc. I showed how to use GitHub Actions workflow and Terraform cloud for my setup. You can use this in your environment using the same workflow, and by changing the terraform file depending upon your BIG-IP configurations. Using similar concepts, you can test BIG-IP configurations in every state of the application delivery lifecycle – development, staging as well as in production. I hope this is helpful. Please share your thoughts and comments below. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7510","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTUxNjRpM0UxRTMzMDczRjE5M0Y3Mw?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wy","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTI4MzVpRDFGRDdGOEI1NzIyRDExOQ?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wz","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM3OWk5RjU0QjE2M0NFODExQ0Yx?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w0","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjE2N2kwM0M4MjJFRDJGQzgyQzRC?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w1","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTQ5ODFpRTcxOTMwNTZDMTI3NkMwNg?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w2","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTE5MTJpMjBBRTAwODNCRkYzMzhBMA?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w3","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtODg5MWlBN0Q5MEVENkM3OTNFQjFF?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w4","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtNjI5MWkxQzUxNTMxNDdGRjI1QUYx?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3w5","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yODcxMjgtMTM4OWk2QzgyOUNGMTk2OTgwRUZE?revision=1\"}"}}],"totalCount":9,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:290960":{"__typename":"Conversation","id":"conversation:290960","topic":{"__typename":"TkbTopicMessage","uid":290960},"lastPostingActivityTime":"2021-02-22T08:24:40.000-08:00","solved":false},"User:user:194339":{"__typename":"User","uid":194339,"login":"ManiGadde","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-11.svg"},"id":"user:194339"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yOTA5NjAtNTgwN2lFQTU5RjdBNUYyOUUzQjYx?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yOTA5NjAtNTgwN2lFQTU5RjdBNUYyOUUzQjYx?revision=1","title":"0151T000003qCMmQAM.png","associationType":"BODY","width":620,"height":686,"altText":null},"TkbTopicMessage:message:290960":{"__typename":"TkbTopicMessage","subject":"NGINX ingress proxy for Consul Service Mesh","conversation":{"__ref":"Conversation:conversation:290960"},"id":"message:290960","revisionNum":1,"uid":290960,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:194339"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":5306},"postTime":"2021-02-22T08:24:40.000-08:00","lastPublishTime":"2021-02-22T08:24:40.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Disclaimer: This blog post is an abridged (NGINX specific) version of the original blog by John Eikenberry at HashiCorp. Consul service mesh provides service-to-service connection authorization and encryption using mutual Transport Layer Security (mTLS). Secure mesh networks require ingress points to act as gateways to enable external traffic to communicate with the internal services. NGINX supports mTLS and can be configured as a robust ingress proxy for your mesh network. For Consul service mesh environments, you can use Consul-template to configure NGINX as a native ingress proxy. This can be beneficial when performance is of utmost importance. \t\t\t\t\t\t\t Below you can walk through a complete example setup. The examples use consul-template to dynamically generate the proxy configuration and the required certificates for the NGINX to communicate directly with the services inside the mesh network. This blog post is only meant to demonstrate features and may not be a production ready or secure deployment. Each of the services are configured for demonstration purposes and will run in the foreground and output its logs to that console. They are all designed to run from files in the same directory. In this blog post, we use the term ingress proxy to describe Nginx. When we use the term sidecar proxy, we mean the Consul Connect proxy for the internal service. Common Infrastructure The example setup below requires Consul, NGINX, and Python. The former is available at the link provided, NGINX and Python should be easily installable with the package manager on any Linux system. The Ingress proxy needs a service to proxy to, for that you need Consul, a service (E.g., a simple webserver), and the Connect sidecar proxy to connect it to the mesh. The ingress proxy will also need the certificates to make the mTLS connection. Start Consul Connect, Consul’s service mesh feature, requires Consul 1.2.0 or newer. First start your agent. $ consul agent -dev\n Start a Webserver For the webserver you will use Python’s simple built-in server included in most Linux distributions and Macs. $ python -m SimpleHTTPServer\n Python’s webserver will listen on port 8000 and publish an index.html by default. For demo purposes, create an index.html for it to publish. $ echo \"Hello from inside the mesh.\" > index.html\n Next, you’ll need to register your “webserver” with Consul. Note, the Connect option registers a sidecar proxy with the service. $ echo '{\n \"service\": {\n \"name\": \"webserver\",\n \"connect\": { \"sidecarservice\": {} },\n \"port\": 8000\n }\n}' > webserver.json\n\n$ consul services register webserver.json\n You also need to start the sidecar. $ consul connect proxy -sidecar-for webserver\n Note, the service is using the built-in sidecar proxy. In production you would probably want to consider using Envoy or NGINX instead. Create the Certificate File Templates To establish a connection with the mesh network, you’ll need to use consul-template to fetch the CA root certificate from the Consul servers as well as the applications leaf certificates, which Consul will generate. You need to create the templates that consul-template will use to generate the certificate files needed for NGINX ingress proxy. The template functions caRoots and caLeaf require consul-template version 0.23.0 or newer. Note, the name, “nginx” used in the leaf certificate templates. It needs to match the name used to register the ingress proxy services with Consul below. ca.crt NGINX requires the CA certificate. $ echo '{{range caRoots}}{{.RootCertPEM}}{{end}}' > ca.crt.tmpl\n Nginx cert.pem and cert.key NGINX requires the certificate and key to be in separate files. $ echo '{{with caLeaf \"nginx\"}}{{.CertPEM}}{{end}}' > cert.pem.tmpl\n$ echo '{{with caLeaf \"nginx\"}}{{.PrivateKeyPEM}}{{end}}' > cert.key.tmpl\n Setup The Ingress Proxies NGINX proxy service needs to be registered with Consul and have a templated configuration file. In each of the templated configuration files, the connect function is called and returns a list of the services with the passed name “webserver” (matching the registered service above). The list Consul creates is used to create the list of back-end servers to which the ingress proxy connections. The ports are set to different values so you can have both proxies running at the same time. First, register the NGINX ingress proxy service with the Consul servers. $ echo '{\n \"service\": {\n \"name\": \"nginx\",\n \"port\": 8081\n }\n}' > nginx-service.json\n\n$ consul services register nginx-service.json\n Next, configure the NGINX configuration file template. Set it to listen on the registered port and route to the Connect-enabled servers retrieved by the Connect call. nginx-proxy.conf.tmpl $ cat > nginx-proxy.conf.tmpl << EOF\ndaemon off;\nmaster_process off;\npid nginx.pid;\nerror_log /dev/stdout;\n\nevents {}\n\nhttp {\n access_log /dev/stdout;\n\n server {\n listen 8081 defaultserver;\n\n location / {\n{{range connect \"webserver\"}}\n proxy_pass https://{{.Address}}:{{.Port}};\n{{end}}\n # these refer to files written by templates above\n proxy_ssl_certificate cert.pem;\n proxy_ssl_certificate_key cert.key;\n proxy_ssl_trusted_certificate ca.crt;\n }\n }\n}\nEOF\n Consul Template The final piece of the puzzle, tying things together are the consul-template configuration files! These are written in HCL, the Hashicorp Configuration Language, and lay out the commands used to run the proxy, the template files, and their destination files. nginx-ingress-config.hcl $ cat > nginx-ingress-config.hcl << EOF\nexec {\n command = \"/usr/sbin/nginx -p . -c nginx-proxy.conf\"\n}\ntemplate {\n source = \"ca.crt.tmpl\"\n destination = \"ca.crt\"\n}\ntemplate {\n source = \"cert.pem.tmpl\"\n destination = \"cert.pem\"\n}\ntemplate {\n source = \"cert.key.tmpl\"\n destination = \"cert.key\"\n}\ntemplate {\n source = \"nginx-proxy.conf.tmpl\"\n destination = \"nginx-proxy.conf\"\n}\nEOF\n Running and Testing You are now ready to run the consul-template managed NGINX ingress proxy. When you run consul-template, it will process each of the templates, fetching the certificate and server information from consul as needed, and render them to their destination files on disk. Once all the templates have been successfully rendered it will run the command starting the proxy. Run the NGINX managing consul-template instance. $ consul-template -config nginx-ingress-config.hcl\n Now with everything running, you are finally ready to test the proxies. $ curl http://localhost:8081\nHello from inside the mesh!\n Conclusion F5 technologies work very well in your Consul environments. In this blog post you walked through setting up NGINX to work as a proxy to provide ingress to services contained in a Consul service mesh. Please reach out to me and the F5-HashiCorp alliance team here if you have any questions, feature requests, or any feedback to make this solution better. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"7531","kudosSumWeight":0,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yOTA5NjAtNTgwN2lFQTU5RjdBNUYyOUUzQjYx?revision=1\"}"}}],"totalCount":1,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:285170":{"__typename":"Conversation","id":"conversation:285170","topic":{"__typename":"TkbTopicMessage","uid":285170},"lastPostingActivityTime":"2020-11-12T02:37:21.000-08:00","solved":false},"User:user:51154":{"__typename":"User","uid":51154,"login":"JRahm","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/images/dS01MTE1NC1uYzdSVFk?image-coordinates=0%2C0%2C1067%2C1067"},"id":"user:51154"},"TkbTopicMessage:message:285170":{"__typename":"TkbTopicMessage","subject":"Lightboard Lessons: Zero Touch Application Deployments with Terraform, Consul, and AS3","conversation":{"__ref":"Conversation:conversation:285170"},"id":"message:285170","revisionNum":1,"uid":285170,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:51154"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1204},"postTime":"2020-11-11T14:36:52.000-08:00","lastPublishTime":"2020-11-11T14:36:52.000-08:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" In this lightboard lesson, I show how you can move from the manual work of traditional app deployments to the automated goodness of zero touch app deployments! This demo solution was shown in a Hashicorp webinar featuring our own Eric Chen, and utilizes Hashicorp's Terraform and Consul applications, as well as the AS3 component of the F5 Automation Toolchain. Resources This demo in detail F5 Terraform automation lab (hosted by WWT, registration required) F5 Resources for Terraform Hands-on Intro to Infrastructure as Code Using Terraform Ready to go! Deploying F5 Infrastructure Using Terraform F5 and Hashicorp Essentials (article series on Terraform, Consul, and Vault) ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"694","kudosSumWeight":0,"repliesCount":2,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:291072":{"__typename":"Conversation","id":"conversation:291072","topic":{"__typename":"TkbTopicMessage","uid":291072},"lastPostingActivityTime":"2020-08-06T14:54:44.000-07:00","solved":false},"User:user:195347":{"__typename":"User","uid":195347,"login":"Mark_Menger","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-10.svg"},"id":"user:195347"},"TkbTopicMessage:message:291072":{"__typename":"TkbTopicMessage","subject":"Manage BIG-IPs in Azure using Terraform Cloud","conversation":{"__ref":"Conversation:conversation:291072"},"id":"message:291072","revisionNum":1,"uid":291072,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:195347"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1033},"postTime":"2020-08-06T14:54:44.000-07:00","lastPublishTime":"2020-08-06T14:54:44.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Introduction \n\n In this article I’ll outline a suite of demonstration resources designed to help you and your IT team explore the possibilities of applying DevOps practices in your own environments. The demonstration resources described below show how tools like Git, HashiCorp Terraform, HashiCorp Sentinel, Chef Inspec and F5's Automation Toolchain can be used to introduce some of the practices listed above to F5 BIG-IPs and the IT services they help deliver. By following along with the README in the demonstration repository and the video walk-throughs listed below, you should be able to run this demonstration on your own. \n\n Software Delivery Key Practices \n\n IT Industry research, such as Accelerate, shows improving a company's ability to deliver software has a significant positive benefit to their overall success. The following practices and design principles are cornerstones to that improvement. \n\n Version control of code and configuration Automation of Deployment Automation of Testing and Test Data Management \"Shifting Left\" on Security Loosely Coupled Architectures Pro-active Notification \n\n Caveats \n\n These repositories use simplifying demonstration shortcuts for password, key, and network security. Production-ready enterprise designs and workflows should be used in place of these shortcuts. DO NOT ASSUME THAT THE CODE AND CONFIGURATION IN THESE REPOSITORIES IS PRODUCTION-READY The particular source control approach shown in this demonstration is one of many. Before using this approach to support your Infrastructure as Code and Configuration Management assets and workflows, you should learn about different patterns of source code management and determine what best fits your team's needs. A variety of tools are used in this demonstration. In most cases they are not exclusively required and can be replaced with other similar tools. The demonstration uses a licensed version of Terraform Cloud in order to demonstrate the capabilities of HashiCorp Sentinel. If you are using the free version of Terraform Cloud you won't be able to try the policy compliance use-cases, and the rest of the demonstration code should work as expected. \n\n Setting up your demonstration automation host \n\n Before running the demonstration code, you'll need to set up the IDE host and the Azure account. Instructions for those steps are here \n\n Video walk-throughs \n\n Fork the repository and open it in Visual Studio Code (1m36s) \n\n Once the tools are installed, you can create your own copy of the repository and open it in your IDE. In the videos, Visual Studio Code is used as the IDE. In order to follow along, you'll need to create your own repository in order to set up the Terraform Cloud configuration and make your own adjustments to build configuration (e.g. the number of application servers deployed) \n\n Set up a Terraform Cloud workspace (1m38s) \n\n Before running the Terraform Cloud workflow, a Terraform Cloud workspace is required. This video steps you through manually configuring the workspace and linking it to your cloned repository. \n\n Programmatically set up Terraform Cloud workspaces for production, test, and development (10m40s) \n\n Setting up the workspaces programmatically has the benefits of rapid consistent results and executable knowledge in the form of scripts and configuration files. In this video we step you through programmatically building workspaces for production, test, and development environments using this repository. We also programmatically configure simple source-controlled compliance Sentinal policies. \n\n Initial build of production, test, and development (7m59s) \n\n Everything should be ready for the first build of your production, test, and development environments. In this video, we step you through manually triggering Terraform Cloud builds. In addition, we'll see the impact of Sentinel policies in use, how to override policies that have been triggered, and the audit trail that results. \n\n Automated testing of production (4m18s) \n\n Once your environment builds have completed, it's critical to validate that they are fit for use. In this video, we step you through a simple set of tests that validate the readiness of the F5 BIG-IPs built by the Terraform Cloud workflow. These tests are not comprehensive, but demonstrate the benefits of an executable \"definition of done.\" The source of an updated version of the Inspec tests used in the demonstration is here. \n\n Manual inspection of production (2m45s) \n\n In this video, we walk through the BIG-IPs that were built in the production environment. We inspect the virtual servers and their associated pools, noting the number of application servers that were built and joined to the pool. \n\n Programmatically add application servers and include them in the BIG-IP virtual server (8m6s) \n\n In this video, we explore the use-case of expanding the pool in the previously built production environment, using a simple change in source control. We'll see the Terraform Cloud workflow automatically trigger a new build based on a merge commit to your cloned repository. New application servers will be built and automatically added to the pool by F5's Service Discovery iApp. \n\n Update WAF from a source control repository (no video walk-through) \n\n We leave it as an exercise for the reader (or possibly an updated video) to look for the WAF deployed with the virtual server. The WAF is retrieved from source control here. \n\n In addition, you can experiment with changing the version of the WAF in the AS3 template in the stanza shown below. Usable values for versions are 0.1.0, 0.1.1, 0.2.0, and 0.2.1. If you choose to do this, follow the same workflow shown in the previous video about scaling the number of application servers. \n\n \n\"ASM_Policy\": {\n \"class\": \"WAF_Policy\",\n \"url\": \"https://github.com/mjmenger/waf-policy/raw/0.1.1/asm_policy.xml\",\n \"ignoreChanges\": false\n}\n \n\n What's next? \n\n If you've followed along through the all of the use-cases in the demonstration repository, you have seen the following: \n\n Source-controlled build of an application environment, including BIG-IPs, virtual servers, pools, and WAF policies. Managed changes with logging of authoring and approvals. Automated scaling of application resources and BIG-IP configuration. Automated updates to BIG-IP WAF policies. \n\n If you want to realize the benefits of these practices for your IT service delivery, please reach out to your F5 account team. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"6609","kudosSumWeight":2,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"Conversation:conversation:278852":{"__typename":"Conversation","id":"conversation:278852","topic":{"__typename":"TkbTopicMessage","uid":278852},"lastPostingActivityTime":"2020-06-19T08:29:19.000-07:00","solved":false},"User:user:321695":{"__typename":"User","uid":321695,"login":"Paul_Pindell","registrationData":{"__typename":"RegistrationData","status":null},"deleted":false,"avatar":{"__typename":"UserAvatar","url":"https://community.f5.com/t5/s/zihoc95639/m_assets/avatars/default/avatar-10.svg"},"id":"user:321695"},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTA2MzRpOUQzRjA0MjRDQTQ3NzMzMg?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTA2MzRpOUQzRjA0MjRDQTQ3NzMzMg?revision=1","title":"0151T000002dnelQAA.png","associationType":"BODY","width":1765,"height":722,"altText":null},"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTM2MzFpMUIyQUIzRUU3MTgzRkVEMg?revision=1\"}":{"__typename":"AssociatedImage","url":"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTM2MzFpMUIyQUIzRUU3MTgzRkVEMg?revision=1","title":"0151T000002dneqQAA.png","associationType":"BODY","width":1392,"height":350,"altText":null},"TkbTopicMessage:message:278852":{"__typename":"TkbTopicMessage","subject":"F5 BIG-IP as a Terminating Gateway for HashiCorp Consul","conversation":{"__ref":"Conversation:conversation:278852"},"id":"message:278852","revisionNum":1,"uid":278852,"depth":0,"board":{"__ref":"Tkb:board:TechnicalArticles"},"author":{"__ref":"User:user:321695"},"teaser@stripHtml({\"removeProcessingText\":true,\"truncateLength\":-1})":"","introduction":"","metrics":{"__typename":"MessageMetrics","views":1014},"postTime":"2020-06-19T08:29:19.000-07:00","lastPublishTime":"2020-06-19T08:29:19.000-07:00","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})":" Our joint customers have asked for it, so the HashiCorp Consul team and the F5 BIG-IP teams have been working to provide this early look at the technology and configurations needed to have BIG-IP perform the Terminating Gateway functionality for HashiCorp Consul. A Bit of an Introduction HashiCorp Consul is a platform that is multi cloud and is used to secure service to service communication. You have all heard about microservices and how within an environment like Consul there is a need to secure and control microservice to microservice communications. But what happens when you want a similar level of security and control when a microservice inside the environment needs to communicate with a service outside of the environment. Enter F5 BIG-IP - the Enterprise Terminating Gateway solution for HashiCorp. HashiCorp has announced the GA of their Terminating Gateway functionality, and we here at F5 want to show our support for this milestone by showing the progress we have made to date in answering the requests of our joint customers. One of the requirements of a Terminating Gateway is that it must respect the security policies defined within Consul. HashiCorp calls these policies Intentions. What Should You Get Out of this Article This article is focused on how BIG-IP when acting as a Terminating Gateway can understand those Intentions and can securely apply those policies/Intentions to either allow or disallow microservice to microservice communications. Update We have been hard at work on this solution, and have created a method to automate the manual processes that I had detailed below. You can skip executing the steps below and jump directly to the new DevCentral Git repository for this solution. Feel free to read the below to get an understanding of the workflows we have automated using the code in the new DevCentral repo. And you can also check out this webinar to hear more about the solution and to see the developer, Shaun Empie, demo the automation of the solution. First Steps Before we dive into the iRulesLX that makes this possible, one must configure the BIG-IP Virtual server to secure the connectivity with mTLS, and configure the pool, profiles, and other configuration options necessary for one's environment. Many here on DevCentral have shown how F5 can perform mTLS with various solutions. Eric Chen has shown how to configure the BIG-IP to use mTLS with Slack. What I want to focus on is how to use an iRuleLX to extract the info necessary to respect the HashiCorp Intentions and allow or disallow a connection based on the HashiCorp Consul Intention. I have to give credit where credit is due. Sanjay Shitole is the one behind the scenes here at F5 along with Dan Callao and Blake Covarrubias from HashiCorp who have worked through the various API touch points, designed the workflow, and F5 Specific iRules and iRulesLX needed to make this function. Now for the Fun Part Once you get your Virtual Server and Pool created the way you would like them with the mTLS certificates etc., you can focus on creating the iLX Workspace where you will write the node.js code and iRules. You can follow the instructions here to create the iLX workspace, add an extension, and an LX plugin. Below is the tcl-based iRule that you will have to add to this workspace. To do this go to Local Traffic > iRules > LX Workspaces and find the workspace you had created in the steps above. In our example, we used \"ConsulWorkSpace\". Paste the text of the rule listed below into the text editor and click save file. There is one variable (sb_debug) you can change in this file depending on the level of logging you want done to the /var/log/ltm logs. The rest of the iRule Grabs the full SNI value from the handshake. This will be parsed later on in the node.js code to populate one of the variables needed for checking the intention of this connection in Consul. The next section grabs the certificate and stores it as a variable so we can later extract the serial_id and the spiffe, which are the other two variables needed to check the Consul Intention. The next step in the iRule is to pass these three variables via an RPC_HANDLE function to the Node.js code we will discuss below. The last section uses that same RPC_HANDLE to get responses back from the node code and either allows or disallows the connection based on the value of the Consul Intention. when RULE_INIT {\n #set static::sb_debug to 2 if you want to enable logging to troubleshoot this iRule, 1 for informational messages, otherwise set to 0\n set static::sb_debug 0\n if {$static::sb_debug > 1} { log local0. \"rule init\" }\n}\n\nwhen CLIENTSSL_HANDSHAKE {\n if { [SSL::extensions exists -type 0] } {\n binary scan [SSL::extensions -type 0] {@9A*} sni_name\n if {$static::sb_debug > 1} { log local0. \"sni name: ${sni_name}\"}\n \n }\n # use the ternary operator to return the servername conditionally\n if {$static::sb_debug > 1} { log local0. \"sni name: [expr {[info exists sni_name] ? ${sni_name} : {not found} }]\"}\n}\n\nwhen CLIENTSSL_CLIENTCERT {\n if {$static::sb_debug > 1} {log local0. \"In CLIENTSSL_CLIENTCERT\"}\n set client_cert [SSL::cert 0]\n}\n\nwhen HTTP_REQUEST {\n set serial_id \"\"\n set spiffe \"\"\n set log_prefix \"[IP::remote_addr]:[TCP::remote_port clientside] [IP::local_addr]:[TCP::local_port clientside]\"\n if { [SSL::cert count] > 0 } {\n HTTP::header insert \"X-ENV-SSL_CLIENT_CERTIFICATE\" [X509::whole [SSL::cert 0]]\n set spiffe [findstr [X509::extensions [SSL::cert 0]] \"Subject Alternative Name\" 39 \",\"]\n if {$static::sb_debug > 1} { log local0. \"<$log_prefix>: SAN: $spiffe\"}\n set serial_id [X509::serial_number $client_cert]\n if {$static::sb_debug > 1} { log local0. \"<$log_prefix>: Serial_ID: $serial_id\"}\n }\n if {$static::sb_debug > 1} { log local0.info \"here is spiffe: $spiffe\" }\n set RPC_HANDLE [ILX::init \"SidebandPlugin\" \"SidebandExt\"]\n if {[catch {ILX::call $RPC_HANDLE \"func\" $sni_name $spiffe $serial_id} result]} {\n if {$static::sb_debug > 1} { log local0.error \"Client - [IP::client_addr], ILX failure: $result\"}\n HTTP::respond 500 content \"Internal server error: Backend server did not respond.\"\n return\n }\n ## return proxy result\n if { $result eq 1 }{\n if {$static::sb_debug > 1} {log local0. \"Is the connection authorized: $result\"}\n } else {\n if {$static::sb_debug > 1} {log local0. \"Connection is not authorized: $result\"}\n HTTP::respond 400 content '{\"status\":\"Not_Authorized\"}' \"Content-Type\" \"application/json\"\n }\n}\n Next is to copy the text of the node.js code below and paste it into the index.js file using the GUI. Here though there are two lines you will have to edit that are unique to your environment. Those two lines are the hostname and the port in the \"const options =\" section. These values will be the IP and port on which your Consul Server is listening for API calls. This node.js takes the three values the tcl-based iRule passed to it, does some regex magic on the sni_name value to get the target variable that is used to check the Consul Intention. It does this by crafting an API call to the consul server API endpoint that includes the Target, the ClientCertURI, and the ClientCertSerial values. The Consul Server responds back, and the node.js code captures that response, and passes a value back to the tcl-based iRule, which means the communication is disallowed or allowed. const http = require(\"http\");\nconst f5 = require(\"f5-nodejs\");\n \n// Initialize ILX Server\nvar ilx = new f5.ILXServer();\nilx.addMethod('func', function(req, res) {\nvar retstr = \"\";\nvar sni_name = req.params()[0];\nvar spiffe = req.params()[1];\nvar serial_id = req.params()[2];\nconst regex = /[^.]*/;\nlet targetarr = sni_name.match(regex);\ntarget = targetarr.toString();\nconsole.log('My Spiffe ID is: ', spiffe);\nconsole.log('My Serial ID is: ', serial_id);\n//Construct request payload\nvar data = JSON.stringify({\n \"Target\": target, \"ClientCertURI\": spiffe, \"ClientCertSerial\": serial_id\n});\n//Strip off newline character(s)\ndata = data.replace(/\\\\n/g, '') ;\n// Construct connection settings\nconst options = {\n hostname: '10.0.0.100',\n port: 8500,\n path: '/v1/agent/connect/authorize',\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n};\n// Construct Consul sideband HTTP Call\nconst myreq = http.request(options, res2 => {\n console.log(`Posting Json to Consul -------> statusCode: ${res2.statusCode}`);\n \n res2.on('data', d => {\n //capture response payload\n process.stdout.write(d);\n retstr += d;\n });\n res2.on('end', d => {\n //Check response for Valid Authorizaion and return back to TCL iRule\n var isVal = retstr.includes(\":true\");\n res.reply(isVal);\n });\n});\n \nmyreq.on('error', error => {\n console.error(error);\n});\n \n// Intiate Consul Call\nmyreq.write(data);\nmyreq.end();\n});\n// Start ILX listener\nilx.listen();\n\n This iRulesLX solution will allow for multiple sources to connect to the BIG-IP Virtual Server, exchange mTLS info, but only allow the connection once the Consul Intentions are verified. If your Intentions looked something similar to the ones below the Client microservice would be allowed to communicate with the services behind the BIG-IP, whereas the socialapp microservice would be blocked at the BIG-IP since we are capturing and respecting the Consul Intentions. So now that we have shown how BIG-IP acts as terminating Gateway for HashiCorp Consul - all the while respecting the Consul Intentions, What’s next? Well next is for F5 and HashiCorp to continue working together on this solution. We intend to take this a level further by creating a prototype that automates the process. The Automated prototype will have a mechanism to listen to changes within the Consul API server, and when a new service is defined behind the BIG-IP acting as the terminating Gateway, the Virtual server, the pools, the ssl profiles, and the iRulesLX workspace can be automatically configured via an AS3 declaration. What Can You Do Next You can find all of the iRules used in this solution in our DevCentral Github repo. Please reach out to me and the F5 HashiCorp Business Development team here if you have any questions, feature requests, or any feedback to make this solution better. ","body@stripHtml({\"removeProcessingText\":true,\"removeSpoilerMarkup\":true,\"removeTocMarkup\":true,\"truncateLength\":-1})@stringLength":"10947","kudosSumWeight":3,"repliesCount":0,"readOnly":false,"images":{"__typename":"AssociatedImageConnection","edges":[{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wx","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTA2MzRpOUQzRjA0MjRDQTQ3NzMzMg?revision=1\"}"}},{"__typename":"AssociatedImageEdge","cursor":"MjQuMTF8Mi4xfG98MjV8X05WX3wy","node":{"__ref":"AssociatedImage:{\"url\":\"https://community.f5.com/t5/s/zihoc95639/images/bS0yNzg4NTItMTM2MzFpMUIyQUIzRUU3MTgzRkVEMg?revision=1\"}"}}],"totalCount":2,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}},"videos":{"__typename":"VideoConnection","edges":[],"totalCount":0,"pageInfo":{"__typename":"PageInfo","hasNextPage":false,"endCursor":null,"hasPreviousPage":false,"startCursor":null}}},"CachedAsset:text:en_US-components/customComponent/CustomComponent-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/customComponent/CustomComponent-1728320186000","value":{"errorMessage":"Error rendering component id: {customComponentId}","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/community/Navbar-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/Navbar-1728320186000","value":{"community":"Community Home","inbox":"Inbox","manageContent":"Manage Content","tos":"Terms of Service","forgotPassword":"Forgot Password","themeEditor":"Theme Editor","edit":"Edit Navigation Bar","skipContent":"Skip to content","migrated-link-9":"Groups","migrated-link-7":"Technical Articles","migrated-link-8":"DevCentral News","migrated-link-1":"Technical Forum","migrated-link-10":"Community Groups","migrated-link-2":"Water Cooler","migrated-link-11":"F5 Groups","migrated-link-0":"Forums","article-series":"Article Series","migrated-link-5":"Community Articles","migrated-link-6":"Articles","security-insights":"Security Insights","migrated-link-3":"CrowdSRC","migrated-link-4":"CodeShare","migrated-link-12":"Events","migrated-link-13":"Suggestions"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarHamburgerDropdown-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarHamburgerDropdown-1728320186000","value":{"hamburgerLabel":"Side Menu"},"localOverride":false},"CachedAsset:text:en_US-components/community/BrandLogo-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/BrandLogo-1728320186000","value":{"logoAlt":"Khoros","themeLogoAlt":"Brand Logo"},"localOverride":false},"CachedAsset:text:en_US-components/community/NavbarTextLinks-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarTextLinks-1728320186000","value":{"more":"More"},"localOverride":false},"CachedAsset:text:en_US-components/authentication/AuthenticationLink-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/authentication/AuthenticationLink-1728320186000","value":{"title.login":"Sign In","title.registration":"Register","title.forgotPassword":"Forgot Password","title.multiAuthLogin":"Sign In"},"localOverride":false},"CachedAsset:text:en_US-components/nodes/NodeLink-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/nodes/NodeLink-1728320186000","value":{"place":"Place {name}"},"localOverride":false},"CachedAsset:text:en_US-components/tags/TagSubscriptionAction-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/tags/TagSubscriptionAction-1728320186000","value":{"success.follow.title":"Following Tag","success.unfollow.title":"Unfollowed Tag","success.follow.message.followAcrossCommunity":"You will be notified when this tag is used anywhere across the communtiy","success.unfollowtag.message":"You will no longer be notified when this tag is used anywhere in this place","success.unfollowtagAcrossCommunity.message":"You will no longer be notified when this tag is used anywhere across the community","unexpected.error.title":"Error - Action Failed","unexpected.error.message":"An unidentified problem occurred during the action you took. Please try again later.","buttonTitle":"{isSubscribed, select, true {Unfollow} false {Follow} other{}}","unfollow":"Unfollow"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageListTabs-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageListTabs-1728320186000","value":{"mostKudoed":"{value, select, IDEA {Most Votes} other {Most Likes}}","mostReplies":"Most Replies","mostViewed":"Most Viewed","newest":"{value, select, IDEA {Newest Ideas} OCCASION {Newest Events} other {Newest Topics}}","newestOccasions":"Newest Events","mostRecent":"Most Recent","noReplies":"No Replies Yet","noSolutions":"No Solutions Yet","solutions":"Solutions","mostRecentUserContent":"Most Recent","trending":"Trending","draft":"Drafts","spam":"Spam","abuse":"Abuse","moderation":"Moderation","tags":"Tags","PAST":"Past","UPCOMING":"Upcoming","sortBymostRecent":"Sort By Most Recent","sortBymostRecentUserContent":"Sort By Most Recent","sortBymostKudoed":"Sort By Most Likes","sortBymostReplies":"Sort By Most Replies","sortBymostViewed":"Sort By Most Viewed","sortBynewest":"Sort By Newest Topics","sortBynewestOccasions":"Sort By Newest Events","otherTabs":" Messages list in the {tab} for {conversationStyle}","guides":"Guides","archives":"Archives"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/QueryHandler-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/QueryHandler-1728320186000","value":{"title":"Query Handler"},"localOverride":false},"Category:category:top":{"__typename":"Category","id":"category:top","nodeType":"category"},"CachedAsset:text:en_US-components/community/NavbarDropdownToggle-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/community/NavbarDropdownToggle-1728320186000","value":{"ariaLabelClosed":"Press the down arrow to open the menu"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/common/OverflowNav-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/common/OverflowNav-1728320186000","value":{"toggleText":"More"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageView/MessageViewInline-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageView/MessageViewInline-1728320186000","value":{"bylineAuthor":"{bylineAuthor}","bylineBoard":"{bylineBoard}","anonymous":"Anonymous","place":"Place {bylineBoard}","gotoParent":"Go to parent {name}"},"localOverride":false},"CachedAsset:text:en_US-components/users/UserLink-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/users/UserLink-1728320186000","value":{"authorName":"View Profile: {author}","anonymous":"Anonymous"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageSubject-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageSubject-1728320186000","value":{"noSubject":"(no subject)"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageBody-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageBody-1728320186000","value":{"showMessageBody":"Show More","mentionsErrorTitle":"{mentionsType, select, board {Board} user {User} message {Message} other {}} No Longer Available","mentionsErrorMessage":"The {mentionsType} you are trying to view has been removed from the community.","videoProcessing":"Video is being processed. Please try again in a few minutes.","bannerTitle":"Video provider requires cookies to play the video. Accept to continue or {url} it directly on the provider's site.","buttonTitle":"Accept","urlText":"watch"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageTime-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageTime-1728320186000","value":{"postTime":"Published: {time}","lastPublishTime":"Last Update: {time}","conversation.lastPostingActivityTime":"Last posting activity time: {time}","conversation.lastPostTime":"Last post time: {time}","moderationData.rejectTime":"Rejected time: {time}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/nodes/NodeIcon-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/nodes/NodeIcon-1728320186000","value":{"contentType":"Content Type {style, select, FORUM {Forum} BLOG {Blog} TKB {Knowledge Base} IDEA {Ideas} OCCASION {Events} other {}} icon"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageUnreadCount-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageUnreadCount-1728320186000","value":{"unread":"{count} unread","comments":"{count, plural, one { unread comment} other{ unread comments}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageViewCount-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageViewCount-1728320186000","value":{"textTitle":"{count, plural,one {View} other{Views}}","views":"{count, plural, one{View} other{Views}}"},"localOverride":false},"CachedAsset:text:en_US-components/kudos/KudosCount-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/kudos/KudosCount-1728320186000","value":{"textTitle":"{count, plural,one {{messageType, select, IDEA{Vote} other{Like}}} other{{messageType, select, IDEA{Votes} other{Likes}}}}","likes":"{count, plural, one{like} other{likes}}"},"localOverride":false},"CachedAsset:text:en_US-components/messages/MessageRepliesCount-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-components/messages/MessageRepliesCount-1728320186000","value":{"textTitle":"{count, plural,one {{conversationStyle, select, IDEA{Comment} OCCASION{Comment} other{Reply}}} other{{conversationStyle, select, IDEA{Comments} OCCASION{Comments} other{Replies}}}}","comments":"{count, plural, one{Comment} other{Comments}}"},"localOverride":false},"CachedAsset:text:en_US-shared/client/components/users/UserAvatar-1728320186000":{"__typename":"CachedAsset","id":"text:en_US-shared/client/components/users/UserAvatar-1728320186000","value":{"altText":"{login}'s avatar","altTextGeneric":"User's avatar"},"localOverride":false}}}},"page":"/tags/TagPage/TagPage","query":{"tagName":"series-f5-and-hashicorp-essentials"},"buildId":"OKtI0OLKuXmERTJKBVqYX","runtimeConfig":{"buildInformationVisible":false,"logLevelApp":"info","logLevelMetrics":"info","openTelemetryClientEnabled":false,"openTelemetryConfigName":"f5","openTelemetryServiceVersion":"24.11.0","openTelemetryUniverse":"prod","openTelemetryCollector":"http://localhost:4318","openTelemetryRouteChangeAllowedTime":"5000","apolloDevToolsEnabled":false},"isFallback":false,"isExperimentalCompile":false,"dynamicIds":["./components/customComponent/CustomComponent/CustomComponent.tsx","./components/community/Navbar/NavbarWidget.tsx","./components/community/Breadcrumb/BreadcrumbWidget.tsx","./components/tags/TagsHeaderWidget/TagsHeaderWidget.tsx","./components/messages/MessageListForNodeByRecentActivityWidget/MessageListForNodeByRecentActivityWidget.tsx","./components/tags/TagSubscriptionAction/TagSubscriptionAction.tsx","../shared/client/components/common/List/ListGroup/ListGroup.tsx","./components/messages/MessageView/MessageView.tsx","./components/messages/MessageView/MessageViewInline/MessageViewInline.tsx"],"appGip":true,"scriptLoader":[]}