{"id":6025,"date":"2020-12-10T06:20:51","date_gmt":"2020-12-10T05:20:51","guid":{"rendered":"http:\/\/andreas-wolter.com\/?p=6025"},"modified":"2020-12-10T06:40:52","modified_gmt":"2020-12-10T05:40:52","slug":"202012-logging-schema-changes-ddl-trigger","status":"publish","type":"post","link":"https:\/\/andreas-wolter.com\/en\/202012-logging-schema-changes-ddl-trigger\/","title":{"rendered":"Logging Schema-changes in a Database using DDL Trigger"},"content":{"rendered":"\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_image-cf5ef0100b929e30f92909e3f7ba52e8\">\n.avia-image-container.av-av_image-cf5ef0100b929e30f92909e3f7ba52e8 img.avia_image{\nbox-shadow:none;\n}\n.avia-image-container.av-av_image-cf5ef0100b929e30f92909e3f7ba52e8 .av-image-caption-overlay-center{\ncolor:#ffffff;\n}\n<\/style>\n<div  class='avia-image-container av-av_image-cf5ef0100b929e30f92909e3f7ba52e8 av-styling- avia-align-center  avia-builder-el-0  el_before_av_heading  avia-builder-el-first '   itemprop=\"image\" itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/ImageObject\" ><div class=\"avia-image-container-inner\"><div class=\"avia-image-overlay-wrap\"><img decoding=\"async\" class='wp-image-6041 avia-img-lazy-loading-not-6041 avia_image ' src=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes.png\" alt='' title='Preview_Logging_Schema_changes'  height=\"626\" width=\"1018\"  itemprop=\"thumbnailUrl\" srcset=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes.png 1018w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes-600x369.png 600w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes-300x184.png 300w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes-768x472.png 768w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes-705x434.png 705w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Preview_Logging_Schema_changes-450x277.png 450w\" sizes=\"(max-width: 1018px) 100vw, 1018px\" \/><\/div><\/div><\/div>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_heading-ea3ac07d1e23e9dba8adfbd2e2c07f73\">\n#top .av-special-heading.av-av_heading-ea3ac07d1e23e9dba8adfbd2e2c07f73{\npadding-bottom:10px;\n}\nbody .av-special-heading.av-av_heading-ea3ac07d1e23e9dba8adfbd2e2c07f73 .av-special-heading-tag .heading-char{\nfont-size:25px;\n}\n.av-special-heading.av-av_heading-ea3ac07d1e23e9dba8adfbd2e2c07f73 .av-subheading{\nfont-size:15px;\n}\n<\/style>\n<div  class='av-special-heading av-av_heading-ea3ac07d1e23e9dba8adfbd2e2c07f73 av-special-heading-h3 blockquote modern-quote  avia-builder-el-1  el_after_av_image  el_before_av_textblock '><h3 class='av-special-heading-tag'  itemprop=\"headline\"  >Logging Schema-changes in a Database using DDL Trigger<\/h3><div class=\"special-heading-border\"><div class=\"special-heading-inner-border\"><\/div><\/div><\/div>\r\n\r\n<section  class='av_textblock_section av-av_textblock-2de302bf1aa3cf4c9157dbe6f50ac7eb '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><p><em>This blog article was first published at <a href=\"https:\/\/techcommunity.microsoft.com\/t5\/azure-sql\/logging-schema-changes-in-a-database-using-ddl-trigger\/ba-p\/1950343\" target=\"_blank\" rel=\"noopener\"><strong>Microsoft-Techncommunity<\/strong>.<\/a><\/em><\/p>\n<p>Every so often I have been asked \u201chow it is possible to log and review the logs when Developers change objects but do not have access to the SQL Audit?\u201d.<\/p>\n<p>Now, even a security person like me should try to understand the real motivation for this before jumping to the conclusion that Auditing is the only right solution.<\/p>\n<p>So first let\u2019s understand the potential motivations:<\/p>\n<h2>What is the purpose?<\/h2>\n<p>Very often, the background is simply to keep a record of who changed which database-objects to answer typical question like:<\/p>\n<ul>\n<li>\u201cDid anyone change any index lately?\u201d<\/li>\n<li>\u201cI thought we had an Index here on this table, did anyone drop it?\u201d<\/li>\n<li>\u201cWho changed my proc?\u201d (Although I would advise to keep a record of all changes within the header of any module as a best practice)<\/li>\n<li>\u201cWhen did the last deployment run\/stop?\u201d<\/li>\n<li>\u201cMy old SQL-Function code is gone; does anyone have a copy?\u201d<\/li>\n<\/ul>\n<p>The motivation is roughly about<strong> troubleshooting schema-changes. <\/strong>The aim is <strong><u>not<\/u> to detect security breaches<\/strong> or even to support tamper-proof security investigations.<\/p>\n<p>If that is the case, my advice here is to not use Auditing at all for such purpose.<br \/>\nThe Auditing feature in SQL Server and Azure SQL Database is really meant to be used by security personae, or Administrators with high privileges:<\/p>\n<ul>\n<li>The ability to create change, stop and remove Audits is collected under one permission: either ALTER ANY SERVER AUDIT or ALTER ANY DATABASE AUDIT, depending on the scope.<\/li>\n<li>To read the audit result, at a minimum the ALTER ANY SERVER AUDIT-permission is required for Audits to the Application or Security Log but CONTROL SERVER for Audits to a file. In Azure SQL Database CONTROL DATABASE is required when using the system function <em>fn_get_audit_file<\/em> to read from a File target in Blob Storage. Event Hub or Log Analytics are accessed outside from the SQL engine and not controlled with SQL-permissions.<\/li>\n<\/ul>\n<p>The above request is much more easily fulfilled with a simple solution that allows the results of the DDL-activities to be stored directly within a database table. This will provide a convenient way to understand what scripts or ad-hoc changes to a database schema happened \u2013 but it will not serve as measure against evil actors\/attackers.<\/p>\n<p style=\"padding-left: 30px;\"><em>Security-Note<\/em><br \/>\nIf the requirement is, to provide an <strong>Audit trail for Security and Compliance reasons<\/strong>, out of reach for normal Database Developers or anyone accessing SQL Server alone, then SQL Auditing is the right solution. DDL Triggers and local tables can be easily tampered with once an attacker elevated to basic datawriter or ddl_admin-level permissions.<\/p>\n<h2>The solution<\/h2>\n<p>If you need to support your Engineering team with a simple record of all DDL statements (Data Definition Language) run against a database, then I recommend using <strong>DDL Triggers<\/strong>.<\/p>\n<p>A DDL Trigger is comparable to a stored procedure except it gets activated when any DDL event for which it was created occurs. The list of Events that can be used is here: <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/triggers\/ddl-events?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener\">DDL Events &#8211; SQL Server | Microsoft Docs<\/a>.<\/p>\n<p style=\"padding-left: 30px;\"><em>Personal experience<\/em><br \/>\nOver the years working on customer systems, I personally found it to be invaluable and as best practice equipped any database that I designed with such a small trigger and DDL-log-table, just in case. It has helped many times to quickly solve issues with deployments scripts, non-scripted changes to the systems, problems with Source Control and simply getting answers quickly.<br \/>\nThe concept is almost trivial and because DDL changes are usually not in performance-critical code-paths, the theoretical overhead on the DDL statement-runtimes is not relevant. (Unless frequent schema-changes are part of a performance-sensitive workload \u2013 in which case I would then question if using DDL is a good idea at all in such a place. By the way: DDL on temporary tables is not caught by DDL Triggers.)<\/p>\n<p>If we want to log \u201calmost any DDL statement\u201d, we can use the keyword DDL_DATABASE_LEVEL_EVENTS and then within the body of the trigger we can ignore certain events.<\/p>\n<p style=\"padding-left: 30px;\"><em>Note<br \/>\n<\/em>Events that typically make sense to ignore are: regular Index Rebuild, Reorganize and Update Statistics \u2013 routines.<br \/>\n&#8211; Rebuild and Reorganize are both covered by the ALTER_INDEX event. But I would recommend keeping an eye on ALTER INDEX \u2026 DISABLE, therefore in my code-example you will find a bit of logic to exclude only ALTER INDEX that is not caused by the DISABLE-option. (\u201cEnable\u201d would be done via a Rebuild, so unfortunately there is a small gap: we will not know when the Index is enabled again. If this turns out to be important, include the Rebuild-option as well, but expect a high volume of events in that case.)<\/p>\n<p>Inside the Trigger we have access to the EVENTDATA()-Function which returns the details on the event in xml-format. The trigger-code extracts the most useful data from it.<br \/>\nThe so captured events can then be written to a local database table, which is much more convenient for the purpose of troubleshooting than having to go to a Security Audit.<\/p>\n<p style=\"padding-left: 30px;\"><em>Note<\/em><br \/>\nIf you are interested in the Set-Options used when the command was run (this can be useful for debugging purposes), then the <em>SetOptions<\/em>-Node below <em>TSQLCommand<\/em> comes in handy.<\/p>\n<p>Finally, we need to make sure that the Trigger will succeed in writing to the table even if the User who triggered the event may not have explicit permissions to write to any table. To keep this example simple my code grants INSERT onto the dedicated table to public. This is the easy way and sufficient for many scenarios. If you need extra security, I recommend using a special account for impersonation during the trigger execution only, using the <a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/execute-as-clause-transact-sql\" target=\"_blank\" rel=\"noopener\">EXECUTE AS-clause<\/a>. At the end of the script, you will find an example of how to go about that. That way you can make sure to have least privileges applied and only when really needed.<\/p>\n<p>Attached you can find the T-SQL Script which will create the following objects:<\/p>\n<ul>\n<li>A Database-Level DDL Trigger<\/li>\n<li>A Table in a dedicated Schema<\/li>\n<li>A stored procedure to purge data from the table when needed.<\/li>\n<\/ul>\n<\/div><\/section>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_image-0a681da07766d6ca13c1284ae9fe2a67\">\n.avia-image-container.av-av_image-0a681da07766d6ca13c1284ae9fe2a67 img.avia_image{\nbox-shadow:none;\n}\n.avia-image-container.av-av_image-0a681da07766d6ca13c1284ae9fe2a67 .av-image-caption-overlay-center{\ncolor:#ffffff;\n}\n<\/style>\n<div  class='avia-image-container av-av_image-0a681da07766d6ca13c1284ae9fe2a67 av-styling- avia-align-center  avia-builder-el-3  el_after_av_textblock  el_before_av_textblock '   itemprop=\"image\" itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/ImageObject\" ><div class=\"avia-image-container-inner\"><div class=\"avia-image-overlay-wrap\"><img decoding=\"async\" class='wp-image-6039 avia-img-lazy-loading-not-6039 avia_image ' src=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/DDLWatchdogTrigger_Objects.png\" alt='' title='DDLWatchdogTrigger_Objects'  height=\"357\" width=\"345\"  itemprop=\"thumbnailUrl\" srcset=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/DDLWatchdogTrigger_Objects.png 345w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/DDLWatchdogTrigger_Objects-290x300.png 290w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/DDLWatchdogTrigger_Objects-36x36.png 36w\" sizes=\"(max-width: 345px) 100vw, 345px\" \/><\/div><\/div><\/div>\r\n\r\n<section  class='av_textblock_section av-av_textblock-2de302bf1aa3cf4c9157dbe6f50ac7eb '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><p>Also, I include a Script with some queries to test.<\/p>\n<p>This is how the results in the table look like after running some DDL-commands:<\/p>\n<\/div><\/section>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_image-f425ef64cac6bf0abbd418ebd6ff6a82\">\n.avia-image-container.av-av_image-f425ef64cac6bf0abbd418ebd6ff6a82 img.avia_image{\nbox-shadow:none;\n}\n.avia-image-container.av-av_image-f425ef64cac6bf0abbd418ebd6ff6a82 .av-image-caption-overlay-center{\ncolor:#ffffff;\n}\n<\/style>\n<div  class='avia-image-container av-av_image-f425ef64cac6bf0abbd418ebd6ff6a82 av-styling- avia-align-center  avia-builder-el-5  el_after_av_textblock  el_before_av_textblock '   itemprop=\"image\" itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/ImageObject\" ><div class=\"avia-image-container-inner\"><div class=\"avia-image-overlay-wrap\"><img decoding=\"async\" class='wp-image-6037 avia-img-lazy-loading-not-6037 avia_image ' src=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log.png\" alt='' title='Contents_DDL_Log'  height=\"366\" width=\"1823\"  itemprop=\"thumbnailUrl\" srcset=\"https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log.png 1823w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-600x120.png 600w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-300x60.png 300w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-768x154.png 768w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-1030x207.png 1030w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-1500x301.png 1500w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-705x142.png 705w, https:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/Contents_DDL_Log-450x90.png 450w\" sizes=\"(max-width: 1823px) 100vw, 1823px\" \/><\/div><\/div><\/div>\r\n\r\n<section  class='av_textblock_section av-av_textblock-2de302bf1aa3cf4c9157dbe6f50ac7eb '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><h2>Documentation-links:<\/h2>\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/triggers\/ddl-triggers?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener\">DDL Triggers <\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/functions\/eventdata-transact-sql\" target=\"_blank\" rel=\"noopener\">EVENTDATA (Transact-SQL)<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/statements?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener\">Transact-SQL statements &#8211; SQL Server<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/t-sql\/statements\/execute-as-clause-transact-sql?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener\">EXECUTE AS Clause (Transact-SQL) &#8211; SQL Server <\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/sql\/relational-databases\/security\/auditing\/sql-server-audit-database-engine?view=sql-server-ver15\" target=\"_blank\" rel=\"noopener\">SQL Server Audit (Database Engine) <\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-sql\/database\/auditing-overview\" target=\"_blank\" rel=\"noopener\">Azure SQL Auditing for Azure SQL Database and Azure Synapse Analytics &#8211; Azure SQL Database <\/a><\/li>\n<\/ul>\n<p>I hope you find <strong><a href=\"http:\/\/andreas-wolter.com\/wp-content\/uploads\/2020\/12\/2020-12_DDLWatchdogTrigger.zip\">this script<\/a> <\/strong>a useful example.<\/p>\n<p>Let me know how you solve similar requirements in the comments below.<\/p>\n<p>Andreas<\/p>\n<\/div><\/section>\r\n\r\n<div  class='hr av-av_hr-0ff602b3e980a3377077ff3c1c834df6 hr-default  avia-builder-el-7  el_after_av_textblock  el_before_av_one_full '><span class='hr-inner '><span class=\"hr-inner-style\"><\/span><\/span><\/div>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_one_full-97c650ae075063b375f558a776c570f8\">\n#top .flex_column.av-av_one_full-97c650ae075063b375f558a776c570f8{\nmargin-top:40px;\nmargin-bottom:40px;\n}\n.flex_column.av-av_one_full-97c650ae075063b375f558a776c570f8{\nborder-radius:0px 0px 0px 0px;\npadding:0px 0px 0px 0px;\n}\n.responsive #top #wrap_all .flex_column.av-av_one_full-97c650ae075063b375f558a776c570f8{\nmargin-top:40px;\nmargin-bottom:40px;\n}\n<\/style>\n<div  class='flex_column av-av_one_full-97c650ae075063b375f558a776c570f8 av_one_full  avia-builder-el-8  el_after_av_hr  el_before_av_social_share  first flex_column_div av-zero-column-padding  '     ><section  class='av_textblock_section av-av_textblock-2de302bf1aa3cf4c9157dbe6f50ac7eb '   itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/BlogPosting\" itemprop=\"blogPost\" ><div class='avia_textblock'  itemprop=\"text\" ><div><\/div>\n<div><\/div>\n<\/div><\/section><\/div>\r\n\r\n<div  class='av-social-sharing-box av-av_social_share-00566587b7355f5f3aec989679437938 av-social-sharing-box-default  avia-builder-el-10  el_after_av_one_full  el_before_av_hr  av-social-sharing-box-fullwidth'><div class=\"av-share-box\"><h5 class='av-share-link-description av-no-toc '>Eintrag teilen<\/h5><ul class=\"av-share-box-list noLightbox\"><li class='av-share-link av-social-link-facebook' ><a target=\"_blank\" aria-label=\"Share on Facebook\" href=\"https:\/\/www.facebook.com\/sharer.php?u=https:\/\/andreas-wolter.com\/en\/202012-logging-schema-changes-ddl-trigger\/&#038;t=Logging%20Schema-changes%20in%20a%20Database%20using%20DDL%20Trigger\" aria-hidden=\"false\" data-av_icon=\"\ue8f3\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on Facebook\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on Facebook<\/span><\/a><\/li><li class='av-share-link av-social-link-twitter' ><a target=\"_blank\" aria-label=\"Share on Twitter\" href=\"https:\/\/twitter.com\/share?text=Logging%20Schema-changes%20in%20a%20Database%20using%20DDL%20Trigger&#038;url=https:\/\/andreas-wolter.com\/en\/?p=6025\" aria-hidden=\"false\" data-av_icon=\"\ue8f1\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on Twitter\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on Twitter<\/span><\/a><\/li><li class='av-share-link av-social-link-linkedin' ><a target=\"_blank\" aria-label=\"Share on LinkedIn\" href=\"https:\/\/linkedin.com\/shareArticle?mini=true&#038;title=Logging%20Schema-changes%20in%20a%20Database%20using%20DDL%20Trigger&#038;url=https:\/\/andreas-wolter.com\/en\/202012-logging-schema-changes-ddl-trigger\/\" aria-hidden=\"false\" data-av_icon=\"\ue8fc\" data-av_iconfont=\"entypo-fontello\" title=\"\" data-avia-related-tooltip=\"Share on LinkedIn\" rel=\"noopener\"><span class='avia_hidden_link_text'>Share on LinkedIn<\/span><\/a><\/li><\/ul><\/div><\/div>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_hr-4474f20d2389e2e5ecf918a02da5132e\">\n#top .hr.hr-invisible.av-av_hr-4474f20d2389e2e5ecf918a02da5132e{\nheight:50px;\n}\n<\/style>\n<div  class='hr av-av_hr-4474f20d2389e2e5ecf918a02da5132e hr-invisible  avia-builder-el-11  el_after_av_social_share  el_before_av_comments_list '><span class='hr-inner '><span class=\"hr-inner-style\"><\/span><\/span><\/div>\r\n\r\n<div  class='av-buildercomment av-av_comments_list-88ce68e426f11248fa394058a3de040f  av-blog-meta-author-disabled av-blog-meta-html-info-disabled'><\/div>\r\n\r\n\n<style type=\"text\/css\" data-created_by=\"avia_inline_auto\" id=\"style-css-av-av_image-51fc29e498d98722ee6b599a65f58998\">\n.avia-image-container.av-av_image-51fc29e498d98722ee6b599a65f58998 img.avia_image{\nbox-shadow:none;\n}\n.avia-image-container.av-av_image-51fc29e498d98722ee6b599a65f58998 .av-image-caption-overlay-center{\ncolor:#ffffff;\n}\n<\/style>\n<div  class='avia-image-container av-av_image-51fc29e498d98722ee6b599a65f58998 av-styling- avia-align-center  avia-builder-el-13  el_after_av_comments_list  avia-builder-el-last '   itemprop=\"image\" itemscope=\"itemscope\" itemtype=\"https:\/\/schema.org\/ImageObject\" ><div class=\"avia-image-container-inner\"><div class=\"avia-image-overlay-wrap\"><img decoding=\"async\" class='wp-image- avia-img-lazy-loading-not- avia_image ' src=\"http:\/\/andreas-wolter.com\/wp-content\/themes\/enfold\/config-templatebuilder\/avia-template-builder\/images\/placeholder.jpg\" alt='' title=''   itemprop=\"thumbnailUrl\"  \/><\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":4,"featured_media":6041,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[132,121,57,56],"tags":[203,205,333],"class_list":["post-6025","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-miscellaneous","category-scripts-en","category-security-en","category-tracing-monitoring-en","tag-best-practices","tag-least-privilege","tag-trigger"],"_links":{"self":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/6025","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/comments?post=6025"}],"version-history":[{"count":13,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/6025\/revisions"}],"predecessor-version":[{"id":6444,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/posts\/6025\/revisions\/6444"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/media\/6041"}],"wp:attachment":[{"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/media?parent=6025"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/categories?post=6025"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andreas-wolter.com\/en\/wp-json\/wp\/v2\/tags?post=6025"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}