Still Hooked on Universal Access or ID(*)?

Published on May 27, 2024

Introduction

When was the last time you checked to see which Dataset and General Resource profiles have a Universal Access or ID(*) with read or higher? You might be shocked by the results. 

Universal Access (UACC) is a well-known (and sometimes popular) term in the Mainframe world – it is the default access you assign to Dataset and General Resource profiles in RACF. Over the years, Mainframe shops have assigned a UACC of READ or higher to many RACF profiles, because it was simple and quick to implement – this means that any user on the system (even undefined users) will benefit from the UACC. To remove some of the risk associated with UACC, you can replace it by defining the entry ‘ID(*)’ on the access control list of the profile. The * means all RACF defined users, so the door is closed on any undefined users (e.g. A Started Task that is running without a valid userid). Note that if a userid has the RACF RESTRICTED attribute, they will not gain any access via UACC or ID(*).

What's Wrong with UACC or ID(*)?

So what is wrong with the use of UACC or ID(*)? Well, the first question that should come to mind: “Is this compatible with our Corporate Security Policy and Standards?”. If those standards include statements such as, “access controls must be on a need to do, need to know; least privilege; group/role based access must be applied; no default access allowed”, then UACC and/or ID(*) is not compatible. 

Zero Trust Considerations

Next, let’s consider the world of Zero Trust – as a reminder, "never trust, always verify", which means that users and devices should not be trusted by default. When a dataset or general resource has a UACC (or ID *) of read or higher, you are declaring that any user on the system is trusted with that level of access. It is saying that any new users defined on this system (even users in years to come who have roles you know nothing about), will have this level of access to this resource and you are agreeing that access with no knowledge of what they will be doing. 

Consider this scenario. Let’s say your SYS1 prefixed datasets have a Universal Access or ID(*) of READ – these datasets are z/OS system libraries, part of the operating system and part of the Trusted Computing Base (everything in a computing system that provides a secure environment for the system to function). Datasets such as SYS1.PARMLIB are considered sensitive – they reveal a lot of information about how your system is configured. If a person is trying to build a picture of your system and its weaknesses (E.g. for malicious reasons), you’ve given them a big advantage in their mission. Don’t get me started on those application related datasets!

In an era of tougher controls and Zero Trust, I would conclude that the use of UACC or ID(*) should be reduced in favour of granting access via groups. I use the word reduced because you probably won’t be able to remove it completely. For example, there are resource classes that use UACC for different purposes, likes NODES. We must also consider other entities, such as catalogs, certain PROGRAM profiles, to name a few, where it’s just not practical to have a UACC of NONE.  

You might be thinking at this point, what about the Global Access Table (GAT)? Yes, this needs to be factored into any efforts to reduce default access of read or higher. I have seen some organisations go to great lengths to clean-up their GAT, favouring proper access control lists where it is practical.

The battle here is between practicality and security. In many Mainframe shops the battle is either “availability vs security” or “performance vs security”. These three enemies of security, (practicality, availability and performance”) always need keeping in their place. In the past availability seemed to trump security very often; today, not so much.

Reducing your dependency on UACC and/or ID(*) requires careful planning, analysis and a phased implementation. You may have many users, including service accounts that are gaining access through the default path. I have included some useful pointers below on ways in which you can start to address this.


Steps to Address UACC and ID(*)

  1. Most important - get buy-in from your management and make sure the work is properly funded.

  2. Educate the systems programming team and other technical teams, so they understand your aims and the risks of not doing this work. They can be your greatest ally if they are on your side; and your greatest enemy if they are not.

  3. If you have zSecure Access Monitor (part of IBM zSecure Admin); Vanguard Cleanup or CA Cleanup, you can use these tools to understand the historical access usage for profiles. Providing you have collected sufficient access usage data to cover different business cycles (so at least 12 months of usage data), you can start to build access controls via groups using the data collected.

  4. SMF data can also be considered for historical access usage, however this is dependent on the audit/logging options in place. For example, if a profile has a universal access of READ, the profile auditing settings should be set to AUDIT(ALL(READ)) to ensure you capture those read events.

  5. Carefully consider what you will convert the access to, or if you really need to. You could create new groups, however, don’t create a giant group where you simply add all users – this is only shifting the problem, not solving it. The best way is to apply the access to existing groups, such as functional, departmental, role-based type groups, or even break-glass. Also question if the access is even required.

  6. When converting profiles, take advantage of IPL windows to make sure you don’t break something.

  7. Update the security standards for your Mainframe controls, stipulating that universal access must always be set to NONE and the use of ID(*) is not allowed. Remember there will be some exceptions - these must be documented and approved.

  8. Implement new Security Monitoring to detect changes to profiles where a UACC and/or ID(*) is specified with read access or higher.

  9. Implement a preventative control through a product like IBM zSecure Command Verifier or Vanguard Policy Manager, to prevent the assignment of UACC and ID(*).

  10. Update any internal request forms/procedures for Dataset or General Resource access where UACC or ID(*) may feature as an option.

  11. Implementing a zero-trust policy in this manner will be far easier if you have a well-structured role-based security system in place. If you don’t it will be far more tricky.


Conclusion

Whilst this blog is centred around IBM RACF terminology, Mainframe installations running CA ACF2 or CA Top Secret as the external security manager (ESM), should also take into consideration the default access methods that can be used to grant all users access to a resource.

Make no mistake, this is not a one-day piece of work; it’s a project and may be complex to implement in your environment. It’s also a delicate balancing act of security/risk vs what is really practical. Don’t forget that compatibility question I asked at the beginning of this blog – is default access of read or higher compatible (today) with the controls your organisation is required to enforce?  I would conclude that it almost certainly is not.

Stay tuned for part two over the coming weeks!


Disclaimer: The views, thoughts, and opinions expressed in this article belong solely to the author.

With grateful thanks to Lennie Dymoke-Bradshaw for his contribution to this blog.

Jamie Pease

Jamie Pease, CISA, CISM, CDPSE, CISSP, MBCS, CITP, is an independent Mainframe Security Consultant with over 25+ years experience in IT Security and was recently Chairman of the GSE UK Security Working Group.

With extensive experience in mainframe security, Jamie is a certified expert dedicated to helping organizations enhance their security posture. His deep knowledge and practical insights make him a valuable resource for addressing the complex challenges of mainframe security. Connect with Jamie on LinkedIn for more insights and updates.