{"id":31054,"date":"2024-11-10T16:32:15","date_gmt":"2024-11-10T15:32:15","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=31054"},"modified":"2025-03-04T11:03:40","modified_gmt":"2025-03-04T10:03:40","slug":"postgresql-security-with-builtin-roles-and-functions","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/","title":{"rendered":"Postgresql Security with Builtin Roles and functions."},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"533\" src=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-1024x533.png\" alt=\"\" class=\"wp-image-31060\" srcset=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-1024x533.png 1024w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-300x156.png 300w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-768x400.png 768w, https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30.png 1400w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-introduction\">Introduction<\/h2>\n\n\n\n<p>As PostgreSQL continues to gain traction in enterprise-grade applications, I am increasingly tasked and asked about implementing robust security policies. And, as most current DBA positions are multi-systems nowadays, I wanted to make a quick summary on roles and how they can be leveraged to implement those policies. For those accustomed to managing accounts through Active Directory Security Groups in SQL Server or leveraging packages in Oracle, transitioning to PostgreSQL&#8217;s security model can present challenges. This blog explores the built-in roles and permission management techniques available &#8220;out of the box&#8221; in PostgreSQL, providing practical examples for DBAs aiming to secure their &#8220;newly&#8221; favorite open-source system \ud83d\ude42<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding Roles and Privileges in PostgreSQL<\/h2>\n\n\n\n<p>In PostgreSQL, roles encompass both users and groups, serving as the cornerstone for a comprehensive user access management system. A role can own database objects and be granted privileges to interact with objects owned by other roles. Roles with login privileges are effectively users, while those without function similarly to groups, but this is just by convention.  Additionally, roles can possess attributes like <code>LOGIN<\/code>, <code>SUPERUSER<\/code>, <code>CREATEDB<\/code>, or <code>CREATEROLE<\/code>, further defining their capabilities within the database environment.<\/p>\n\n\n\n<p><strong>Orthogonality of Roles:<\/strong><br>Roles have an orthogonality property, meaning each role has a distinct set of privileges. Modifying one role only impacts that role, maintaining a clear separation of permissions. The inheritance property allows roles to inherit privileges from other roles without breaking this rule, providing flexibility in permission management.<\/p>\n\n\n\n<p><strong>Privileges in PostgreSQL:<\/strong><br>Privileges are defined access rights to database objects, including common actions like <code>SELECT<\/code>, <code>INSERT<\/code>, <code>UPDATE<\/code>, <code>DELETE<\/code>, and <code>EXECUTE<\/code>. The system uses <code>GRANT<\/code> and <code>REVOKE<\/code> commands to manage these privileges, allowing fine-grained control over who can do what within the database.<\/p>\n\n\n\n<p>To review existing roles, you can query the system catalogs:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nSELECT rolname FROM pg_roles;\nSELECT usename FROM pg_shadow;\n<\/pre><\/div>\n\n\n<p><a href=\"https:\/\/www.postgresql.org\/docs\/current\/view-pg-shadow.html\">PostgreSQL: Documentation:\u00a0pg_shadow<\/a><br><a href=\"https:\/\/www.postgresql.org\/docs\/current\/view-pg-shadow.html\">PostgreSQL: Documentation: pg_roles<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Hierarchical Role System and Practical Examples<\/h2>\n\n\n\n<p>PostgreSQL&#8217;s role system supports membership, facilitating a hierarchical approach to permissions. Roles can inherit privileges from parent roles, streamlining permission management. Let&#8217;s explore practical scenarios demonstrating how to create roles with specific privileges, manage role memberships, and leverage <code>GRANT<\/code> and <code>REVOKE<\/code> for precise access control.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Example: Managing Permissions for Dev and QA Teams<\/strong><\/h3>\n\n\n\n<p><strong>1. Create Roles for Teams<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n-- Create team roles\nCREATE ROLE dev_team;\nCREATE ROLE qa_team;\n<\/pre><\/div>\n\n\n<p><strong>2. Create Individual User Roles and Assign Them to Teams<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n-- Create user roles with login privileges\nCREATE ROLE emma LOGIN PASSWORD &#039;emma_pass&#039;;\nCREATE ROLE mirka LOGIN PASSWORD &#039;mirka_pass&#039;;\n\n-- Assign users to their respective teams\nGRANT dev_team TO emma;\nGRANT qa_team TO mirka;\n<\/pre><\/div>\n\n\n<p><strong>3. Assign Privileges to Team Roles<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n-- Grant privileges to team roles\nGRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO dev_team;\nGRANT SELECT ON ALL TABLES IN SCHEMA public TO qa_team;\n<\/pre><\/div>\n\n\n<p>In this setup, Alice and Bob inherit the privileges of their respective teams due to the default <code>INHERIT<\/code> attribute.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Advanced Role Management: INHERIT and NOINHERIT<\/h2>\n\n\n\n<p>The <code>INHERIT<\/code> attribute plays a key role in PostgreSQL\u2019s permission system, allowing roles to automatically inherit privileges from roles they are members of. Conversely, the <code>NOINHERIT<\/code> attribute and the <code>SET ROLE<\/code> command offers flexibility in access control, enabling scenarios where privileges need to be tightly controlled.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>INHERIT (Default Behavior)<\/strong><\/h3>\n\n\n\n<p>A role with the <code>INHERIT<\/code> attribute automatically inherits all the privileges of the roles it is a member of. For example, if role <strong>A<\/strong> is a member of role <strong>B<\/strong>, and role <strong>B<\/strong> has the <code>SELECT<\/code> privilege on a table, role <strong>A<\/strong> will also be able to select from that table due to inheritance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>NOINHERIT<\/strong><\/h3>\n\n\n\n<p>If a role is created with the <code>NOINHERIT<\/code> attribute, it does not automatically inherit privileges from roles it is a member of. However, the role can still use the <code>SET ROLE<\/code> command to temporarily assume the privileges of another role it&#8217;s a member of.<\/p>\n\n\n\n<p><strong>Creating and Modifying Roles with INHERIT or NOINHERIT<\/strong><\/p>\n\n\n\n<p>To create a role with <code>NOINHERIT<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nCREATE ROLE auditor WITH LOGIN NOINHERIT;\n<\/pre><\/div>\n\n\n<p>To alter an existing role to <code>NOINHERIT<\/code>:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nALTER ROLE auditor NOINHERIT;\n<\/pre><\/div>\n\n\n<p><strong>Using SET ROLE to Assume Privileges<\/strong><\/p>\n\n\n\n<p>Even if a role is defined with <code>NOINHERIT<\/code>, it can assume the privileges of another role it&#8217;s a member of using the <code>SET ROLE<\/code> command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n-- Assume the privileges of another role\nSET ROLE dev_team;\n\n-- Perform actions with dev_team privileges\n\n-- Revert back to original role\nRESET ROLE;\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\"><strong>Practical Use Case<\/strong><\/h3>\n\n\n\n<p>The <code>NOINHERIT<\/code> option is particularly useful in scenarios where you want to tightly control access to certain operations or objects. For example, you might create an <code>audit_role<\/code> with access to sensitive logs and only allow certain users to assume this role explicitly when needed, instead of automatically inheriting those privileges.<\/p>\n\n\n\n<p>By carefully designing your role hierarchy and using the <code>INHERIT<\/code> and <code>NOINHERIT<\/code> attributes appropriately, you can create a robust security model that provides flexibility while ensuring that access to critical or sensitive operations and data is tightly controlled.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Best Practices for Secure and Efficient Permission Management<\/h2>\n\n\n\n<p>Adopting the <strong>principle of least privilege<\/strong>, utilizing groups for role organization, and conducting regular audits are pivotal strategies for maintaining a secure and efficient permission environment. These practices help minimize risks and ensure that roles are aligned with current security policies and operational requirements.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Implementing the Principle of Least Privilege<\/strong><\/h3>\n\n\n\n<p>This principle involves granting users only the permissions they need to perform their tasks. While it can be challenging to implement, it&#8217;s crucial for database security.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Use Predefined Roles:<\/strong> Start by leveraging PostgreSQL&#8217;s predefined roles to assign common sets of privileges without granting superuser status.<\/li>\n\n\n\n<li><strong>Regular Audits:<\/strong> Periodically review role memberships and privileges to ensure they are still appropriate.<\/li>\n\n\n\n<li><strong>Limit Superuser Access:<\/strong> Restrict the number of superusers and avoid using superuser roles for routine tasks.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Integration with External Authentication Systems<\/strong><\/h3>\n\n\n\n<p>In SQL Server environments, it&#8217;s common to use external user management systems like Active Directory. While PostgreSQL can integrate with such systems, it&#8217;s less common. However, tools like RedHat IdM are increasingly used alongside automation and DevOps practices to manage users and roles effectively.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">PostgreSQL&#8217;s Predefined Roles<\/h2>\n\n\n\n<p>The evolution of PostgreSQL&#8217;s built-in roles reflects its growing use in critical production environments. These roles provide operational flexibility and enhanced security, aligning PostgreSQL more closely with traditional RDBMS like Oracle or SQL Server.<\/p>\n\n\n\n<p>Refer to the official documentation for more details: <br><a href=\"https:\/\/www.postgresql.org\/docs\/current\/predefined-roles.html\">PostgreSQL: Documentation:\u00a0Predefined Roles<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Useful Predefined Roles<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>pg_read_all_settings<\/code><\/strong>: Allows reading of all configuration variables without needing to be a superuser.<\/li>\n\n\n\n<li><strong><code>pg_read_all_stats<\/code><\/strong>: Allows reading of all statistics. Monitoring tools like Prometheus and Percona Monitoring and Management (PMM) utilize this role.<\/li>\n\n\n\n<li><strong><code>pg_stat_scan_tables<\/code><\/strong>: Allows reading of all statistics from <code>pg_stat_all_tables<\/code> and <code>pg_statio_all_tables<\/code>.<\/li>\n\n\n\n<li><strong><code>pg_monitor<\/code><\/strong>: Combines the above roles, providing comprehensive monitoring capabilities.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Specialized Access Control Techniques<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Granting Schema-only Access<\/strong><\/h3>\n\n\n\n<p>Granting schema-only access in PostgreSQL is a strategic approach to provide users with the ability to view and understand database structures without granting them access to the actual data. This is particularly useful in environments where developers or auditors need to understand database layouts, write SQL queries, or perform schema migrations without the risk of accessing sensitive data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Using USAGE Permissions on Schemas<\/strong><\/h4>\n\n\n\n<p>The <code>USAGE<\/code> privilege on a schema allows a role to access objects within the schema (to see the objects). However, it doesn&#8217;t allow reading or modifying the data in those objects without additional permissions.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Granting Schema-only Access: Step-by-Step<\/strong><\/h4>\n\n\n\n<p><strong>1. Grant USAGE Permission on Schemas<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nGRANT USAGE ON SCHEMA public TO schema_viewer;\n<\/pre><\/div>\n\n\n<p><strong>2. Grant SELECT Permission on System Catalogs<\/strong><\/p>\n\n\n\n<p>To enable access to object definitions, grant <code>SELECT<\/code> on the system catalogs in the <code>pg_catalog<\/code> schema:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nGRANT SELECT ON ALL TABLES IN SCHEMA pg_catalog TO schema_viewer;\n<\/pre><\/div>\n\n\n<p><strong>3. Restrict Access to Data<\/strong><\/p>\n\n\n\n<p>Ensure that the role does not have <code>SELECT<\/code> permission on the tables containing actual data.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Advanced Use: Creating Views for Controlled Access<\/strong><\/h4>\n\n\n\n<p>For more granular control, you can create views that expose the necessary metadata while filtering out sensitive information.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nCREATE VIEW custom_table_metadata AS\nSELECT tablename, tableowner\nFROM pg_tables\nWHERE schemaname = &#039;public&#039;;\n\nGRANT SELECT ON custom_table_metadata TO schema_viewer;\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\"><strong>Use Cases<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Auditing:<\/strong> Auditors can verify the structure and integrity of the database schema without accessing data.<\/li>\n\n\n\n<li><strong>Development:<\/strong> Developers can write and test queries, ensuring they are syntactically correct and optimized without requiring access to production data.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Automating the Process<\/strong><\/h4>\n\n\n\n<p>For environments where new schemas or permissions need to be managed dynamically, consider automating these grants through scripts or configuration management tools like Ansible, Puppet, or Chef. Automation ensures consistency, reduces human error, and can be integrated into CI\/CD pipelines for agile development practices.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Encapsulating Permissions Through Functions<\/strong><\/h3>\n\n\n\n<p>Creating administrative functions with the <code>SECURITY DEFINER<\/code> attribute allows for encapsulating permissions, offering a method to manage user actions securely and efficiently.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Example: Dropping a User with a Security Definer Function<\/strong><\/h4>\n\n\n\n<p><strong>Create the Administrative Function<\/strong><\/p>\n\n\n\n<p>When you create a function with the&nbsp;<code>SECURITY DEFINER<\/code>&nbsp;attribute, which means the function will execute with the privileges of the user who defines it (typically a superuser or a user with the necessary administrative privileges). Ensure that this function carefully validates its inputs to prevent security issues, such as SQL injection or unauthorized actions.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nCREATE OR REPLACE FUNCTION drop_user_function(target_username TEXT)\nRETURNS VOID AS $$\nBEGIN\n    -- Validate that the target user exists\n    IF EXISTS (SELECT FROM pg_roles WHERE rolname = target_username) THEN\n        EXECUTE format(&#039;DROP ROLE %I&#039;, target_username);\n    ELSE\n        RAISE EXCEPTION &#039;User &quot;%&quot; does not exist.&#039;, target_username;\n    END IF;\nEND;\n$$ LANGUAGE plpgsql SECURITY DEFINER;\n<\/pre><\/div>\n\n\n<p><strong>Set the Function&#8217;s Ownership and Permissions<\/strong><\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n-- Assume the function is created by a superuser or admin role\nALTER FUNCTION drop_user_function(TEXT) OWNER TO admin_user;\n\n-- Revoke default permissions and grant execute to specific roles\nREVOKE ALL ON FUNCTION drop_user_function(TEXT) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION drop_user_function(TEXT) TO user_manager_role;\n<\/pre><\/div>\n\n\n<p><strong>Use the Function<\/strong><\/p>\n\n\n\n<p>A user with execute privileges on this function can drop a user by calling:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\nSELECT drop_user_function(&#039;user_to_drop&#039;);\n<\/pre><\/div>\n\n\n<h4 class=\"wp-block-heading\"><strong>Security Considerations<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Validate Inputs:<\/strong> Always validate inputs within <code>SECURITY DEFINER<\/code> functions to prevent SQL injection attacks or unauthorized actions.<\/li>\n\n\n\n<li><strong>Limit Permissions:<\/strong> Restrict execute permissions on the function to specific roles or users.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>With PostgreSQL&#8217;s role and permission management features, DBAs can create a secure and efficient database environment tailored to their organization&#8217;s needs. Understanding and properly implementing role inheritance, predefined roles, and specialized access controls are crucial steps toward this goal. By adopting best practices such as the principle of least privilege, regular audits, and careful use of <code>SECURITY DEFINER<\/code> functions, you can enhance the security and operational effectiveness of your database environments. Additionally, if you are in a position of having to manage users&#8217; permissions on a PostgreSQL cluster, you should enable a monitor tool of your own or with a third-party application to be sure to manage who has access to what regardless of whether you are going to integrate with IdMs and Active Directory\/Entra capabilities&#8230; Small hint, if you monitor user access, refreshing your data every 5s is not recommended as it would put unnecessary pressure on the system with no added value since user grants are not that frequent in most cases and enterprise RDBMS, remember that you have an application at the front end&#8230;<br><br>If you want to read more on PostgreSQL security I recommend those 2 blogs as well : <br><br><a href=\"https:\/\/www.percona.com\/blog\/postgresql-database-security-best-practices\/\">Percona Blog : PostgreSQL Database Security Best Practices<\/a><br><a href=\"https:\/\/www.enterprisedb.com\/blog\/how-to-secure-postgresql-security-hardening-best-practices-checklist-tips-encryption-authentication-vulnerabilities\">EDB &#8211; Dave Page Blog :How to Secure PostgreSQL: Security Hardening Best Practices &amp; Tips<\/a><br><a href=\"https:\/\/www.dbi-services.com\/blog\/modifying-pg_hba-conf-from-inside-postgresql\/\">dbi Blog &#8211; Daniel Westermann : Modifying pg_hba.conf from inside PostgreSQL <\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><br><br><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction As PostgreSQL continues to gain traction in enterprise-grade applications, I am increasingly tasked and asked about implementing robust security policies. And, as most current DBA positions are multi-systems nowadays, I wanted to make a quick summary on roles and how they can be leveraged to implement those policies. For those accustomed to managing accounts [&hellip;]<\/p>\n","protected":false},"author":153,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[229,83,149],"tags":[77,3269,3117,3268],"type_dbi":[2749],"class_list":["post-31054","post","type-post","status-publish","format-standard","hentry","category-database-administration-monitoring","category-postgresql","category-security","tag-postgresql","tag-predefined-roles","tag-roles","tag-user-permissions","type-postgresql"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Postgresql Security with Builtin Roles and functions. - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Postgresql Security with Builtin Roles and functions.\" \/>\n<meta property=\"og:description\" content=\"Introduction As PostgreSQL continues to gain traction in enterprise-grade applications, I am increasingly tasked and asked about implementing robust security policies. And, as most current DBA positions are multi-systems nowadays, I wanted to make a quick summary on roles and how they can be leveraged to implement those policies. For those accustomed to managing accounts [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-11-10T15:32:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-04T10:03:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1400\" \/>\n\t<meta property=\"og:image:height\" content=\"729\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Adrien Obernesser\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Adrien Obernesser\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/\"},\"author\":{\"name\":\"Adrien Obernesser\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"headline\":\"Postgresql Security with Builtin Roles and functions.\",\"datePublished\":\"2024-11-10T15:32:15+00:00\",\"dateModified\":\"2025-03-04T10:03:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/\"},\"wordCount\":1593,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/image-30-1024x533.png\",\"keywords\":[\"PostgreSQL\",\"Predefined Roles\",\"roles\",\"User Permissions\"],\"articleSection\":[\"Database Administration &amp; Monitoring\",\"PostgreSQL\",\"Security\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/\",\"name\":\"Postgresql Security with Builtin Roles and functions. - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/image-30-1024x533.png\",\"datePublished\":\"2024-11-10T15:32:15+00:00\",\"dateModified\":\"2025-03-04T10:03:40+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/fd2ab917212ce0200c7618afaa7fdbcd\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/image-30.png\",\"contentUrl\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/2\\\/2024\\\/02\\\/image-30.png\",\"width\":1400,\"height\":729},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/postgresql-security-with-builtin-roles-and-functions\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Postgresql Security with Builtin Roles and functions.\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/fd2ab917212ce0200c7618afaa7fdbcd\",\"name\":\"Adrien Obernesser\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g\",\"caption\":\"Adrien Obernesser\"},\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/adrienobernesser\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Postgresql Security with Builtin Roles and functions. - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/","og_locale":"en_US","og_type":"article","og_title":"Postgresql Security with Builtin Roles and functions.","og_description":"Introduction As PostgreSQL continues to gain traction in enterprise-grade applications, I am increasingly tasked and asked about implementing robust security policies. And, as most current DBA positions are multi-systems nowadays, I wanted to make a quick summary on roles and how they can be leveraged to implement those policies. For those accustomed to managing accounts [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/","og_site_name":"dbi Blog","article_published_time":"2024-11-10T15:32:15+00:00","article_modified_time":"2025-03-04T10:03:40+00:00","og_image":[{"width":1400,"height":729,"url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30.png","type":"image\/png"}],"author":"Adrien Obernesser","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Adrien Obernesser","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/"},"author":{"name":"Adrien Obernesser","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"headline":"Postgresql Security with Builtin Roles and functions.","datePublished":"2024-11-10T15:32:15+00:00","dateModified":"2025-03-04T10:03:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/"},"wordCount":1593,"commentCount":0,"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-1024x533.png","keywords":["PostgreSQL","Predefined Roles","roles","User Permissions"],"articleSection":["Database Administration &amp; Monitoring","PostgreSQL","Security"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/","url":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/","name":"Postgresql Security with Builtin Roles and functions. - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#primaryimage"},"image":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30-1024x533.png","datePublished":"2024-11-10T15:32:15+00:00","dateModified":"2025-03-04T10:03:40+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#primaryimage","url":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30.png","contentUrl":"https:\/\/www.dbi-services.com\/blog\/wp-content\/uploads\/sites\/2\/2024\/02\/image-30.png","width":1400,"height":729},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/postgresql-security-with-builtin-roles-and-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Postgresql Security with Builtin Roles and functions."}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/fd2ab917212ce0200c7618afaa7fdbcd","name":"Adrien Obernesser","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc9316c729e50107159e0a1e631b9c1742ce8898576887d0103c83b1ca3bc9e6?s=96&d=mm&r=g","caption":"Adrien Obernesser"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/adrienobernesser\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/31054","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/153"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=31054"}],"version-history":[{"count":70,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/31054\/revisions"}],"predecessor-version":[{"id":35720,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/31054\/revisions\/35720"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=31054"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=31054"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=31054"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=31054"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}